📄 wcsftime.c
字号:
/***
*wcsftime.c - String Format Time
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
*
*******************************************************************************/
#include <cruntime.h>
#include <internal.h>
#include <mtdll.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <time.h>
#include <dbgint.h>
#include <malloc.h>
#include <errno.h>
#include <locale.h>
#include <setlocal.h>
/* Prototypes for local routines */
static BOOL __cdecl _W_expandtime(
_locale_t plocinfo,
wchar_t specifier,
const struct tm *tmptr,
wchar_t **out,
size_t *count,
struct __lc_time_data *lc_time,
unsigned alternate_form);
static void __cdecl _W_store_str (wchar_t *in, wchar_t **out, size_t *count);
static void __cdecl _W_store_num (int num, int digits, wchar_t **out, size_t *count,
unsigned no_lead_zeros);
static void __cdecl _W_store_number (int num, wchar_t **out, size_t *count);
static BOOL __cdecl _W_store_winword (
_locale_t plocinfo,
int field_code,
const struct tm *tmptr,
wchar_t **out,
size_t *count,
struct __lc_time_data *lc_time);
/* Codes for __lc_time_data ww_* fields for _W_store_winword */
#define WW_SDATEFMT 0
#define WW_LDATEFMT 1
#define WW_TIMEFMT 2
#define TIME_SEP L':'
/* get a copy of the current day names */
extern "C" wchar_t * __cdecl _W_Getdays_l (
_locale_t plocinfo
)
{
const struct __lc_time_data *pt;
size_t n, len = 0;
wchar_t *p;
_LocaleUpdate _loc_update(plocinfo);
pt = __LC_TIME_CURR(_loc_update.GetLocaleT()->locinfo);
for (n = 0; n < 7; ++n)
len += wcslen(pt->_W_wday_abbr[n]) + wcslen(pt->_W_wday[n]) + 2;
p = (wchar_t *)_malloc_crt((len + 1) * sizeof(wchar_t));
if (p != 0) {
wchar_t *s = p;
for (n = 0; n < 7; ++n) {
*s++ = TIME_SEP;
_ERRCHECK(wcscpy_s(s, (len + 1) - (s - p), pt->_W_wday_abbr[n]));
s += wcslen(s);
*s++ = TIME_SEP;
_ERRCHECK(wcscpy_s(s, (len + 1) - (s - p), pt->_W_wday[n]));
s += wcslen(s);
}
*s++ = L'\0';
}
return (p);
}
extern "C" wchar_t * __cdecl _W_Getdays (
void
)
{
return _W_Getdays_l(NULL);
}
/* get a copy of the current month names */
extern "C" wchar_t * __cdecl _W_Getmonths_l (
_locale_t plocinfo
)
{
const struct __lc_time_data *pt;
size_t n, len = 0;
wchar_t *p;
_LocaleUpdate _loc_update(plocinfo);
pt = __LC_TIME_CURR(_loc_update.GetLocaleT()->locinfo);
for (n = 0; n < 12; ++n)
len += wcslen(pt->_W_month_abbr[n]) + wcslen(pt->_W_month[n]) + 2;
p = (wchar_t *)_malloc_crt((len + 1) * sizeof(wchar_t));
if (p != 0) {
wchar_t *s = p;
for (n = 0; n < 12; ++n) {
*s++ = TIME_SEP;
_ERRCHECK(wcscpy_s(s, (len + 1) - (s - p), pt->_W_month_abbr[n]));
s += wcslen(s);
*s++ = TIME_SEP;
_ERRCHECK(wcscpy_s(s, (len + 1) - (s - p), pt->_W_month[n]));
s += wcslen(s);
}
*s++ = L'\0';
}
return (p);
}
extern "C" wchar_t * __cdecl _W_Getmonths (
void
)
{
return _W_Getmonths_l(NULL);
}
/* get a copy of the current time locale information */
extern "C" void * __cdecl _W_Gettnames_l (
_locale_t plocinfo
)
{
const struct __lc_time_data *pt;
size_t n, len = 0;
size_t footprint =
sizeof(*pt) % sizeof(wchar_t) == 0
? sizeof(*pt)
: (sizeof(*pt) / sizeof(wchar_t) + 1) * sizeof(wchar_t);
unsigned char *p;
_LocaleUpdate _loc_update(plocinfo);
pt = __LC_TIME_CURR(_loc_update.GetLocaleT()->locinfo);
for (n = 0; n < 7; ++n)
len += wcslen(pt->_W_wday_abbr[n]) + wcslen(pt->_W_wday[n]) + 2;
for (n = 0; n < 12; ++n)
len += wcslen(pt->_W_month_abbr[n]) + wcslen(pt->_W_month[n]) + 2;
len += wcslen(pt->_W_ampm[0]) + wcslen(pt->_W_ampm[1]) + 2;
len += wcslen(pt->_W_ww_sdatefmt) + 1;
len += wcslen(pt->_W_ww_ldatefmt) + 1;
len += wcslen(pt->_W_ww_timefmt) + 1;
p = (unsigned char *)_malloc_crt(len * sizeof(wchar_t) + footprint);
if (p != 0) {
struct __lc_time_data *pn = (struct __lc_time_data *)p;
wchar_t *s = (wchar_t *)(p + footprint);
const wchar_t *olds = s;
memcpy(pn, pt, sizeof (*pt));
for (n = 0; n < 7; ++n) {
pn->_W_wday_abbr[n] = s;
_ERRCHECK(wcscpy_s(s, len - (s - olds), pt->_W_wday_abbr[n]));
s += wcslen(s) + 1;
pn->_W_wday[n] = s;
_ERRCHECK(wcscpy_s(s, len - (s - olds), pt->_W_wday[n]));
s += wcslen(s) + 1;
}
for (n = 0; n < 12; ++n) {
pn->_W_month_abbr[n] = s;
_ERRCHECK(wcscpy_s(s, len - (s - olds), pt->_W_month_abbr[n]));
s += wcslen(s) + 1;
pn->_W_month[n] = s;
_ERRCHECK(wcscpy_s(s, len - (s - olds), pt->_W_month[n]));
s += wcslen(s) + 1;
}
pn->_W_ampm[0] = s;
_ERRCHECK(wcscpy_s(s, len - (s - olds), pt->_W_ampm[0]));
s += wcslen(s) + 1;
pn->_W_ampm[1] = s;
_ERRCHECK(wcscpy_s(s, len - (s - olds), pt->_W_ampm[1]));
s += wcslen(s) + 1;
pn->_W_ww_sdatefmt = s;
_ERRCHECK(wcscpy_s(s, len - (s - olds), pt->_W_ww_sdatefmt));
s += wcslen(s) + 1;
pn->_W_ww_ldatefmt = s;
_ERRCHECK(wcscpy_s(s, len - (s - olds), pt->_W_ww_ldatefmt));
s += wcslen(s) + 1;
pn->_W_ww_timefmt = s;
_ERRCHECK(wcscpy_s(s, len - (s - olds), pt->_W_ww_timefmt));
}
return (p);
}
extern "C" void * __cdecl _W_Gettnames (
void
)
{
return _W_Gettnames_l(NULL);
}
/***
*size_t _Wcsftime(string, maxsize, format,
* timeptr, lc_time) - Format a time string for a given locale
*
*Purpose:
* Place characters into the user's output buffer expanding time
* format directives as described in the user's control string.
* Use the supplied 'tm' structure for time data when expanding
* the format directives. Use the locale information at lc_time.
* [ANSI]
*
*Entry:
* wchar_t *string = pointer to output string
* size_t maxsize = max length of string
* const wchar_t *format = format control string
* const struct tm *timeptr = pointer to tb data structure
* struct __lc_time_data *lc_time = pointer to locale-specific info
* (passed as void * to avoid type mismatch with C++)
*
*Exit:
* !0 = If the total number of resulting characters including the
* terminating null is not more than 'maxsize', then return the
* number of chars placed in the 'string' array (not including the
* null terminator).
*
* 0 = Otherwise, return 0 and the contents of the string are
* indeterminate.
*
*Exceptions:
*
*******************************************************************************/
extern "C" size_t __cdecl _Wcsftime_l (
wchar_t *string,
size_t maxsize,
const wchar_t *format,
const struct tm *timeptr,
void *lc_time_arg,
_locale_t plocinfo
)
{
unsigned alternate_form;
struct __lc_time_data *lc_time;
BOOL failed=FALSE; /* true if a failure was reported to us */
size_t left; /* space left in output string */
wchar_t* strstart = string;
_LocaleUpdate _loc_update(plocinfo);
_VALIDATE_RETURN( ( string != NULL ), EINVAL, 0)
_VALIDATE_RETURN( ( maxsize != 0 ), EINVAL, 0)
*string = L'\0';
_VALIDATE_RETURN( ( format != NULL ), EINVAL, 0)
// Validated below
// _VALIDATE_RETURN( ( timeptr != NULL ), EINVAL, 0)
lc_time = lc_time_arg == 0 ? _loc_update.GetLocaleT()->locinfo->lc_time_curr :
(struct __lc_time_data *)lc_time_arg;
/* Copy maxsize into temp. */
left = maxsize;
/* Copy the input string to the output string expanding the format
designations appropriately. Stop copying when one of the following
is true: (1) we hit a null char in the input stream, or (2) there's
no room left in the output stream. */
while (left > 0)
{
switch(*format)
{
case(L'\0'):
/* end of format input string */
goto done;
case(L'%'):
/* Format directive. Take appropriate action based
on format control character. */
/* validation section */
_VALIDATE_RETURN(timeptr != NULL, EINVAL, 0);
format++; /* skip over % char */
/* process flags */
alternate_form = 0;
if (*format == L'#')
{
alternate_form = 1;
format++;
}
if(!_W_expandtime (_loc_update.GetLocaleT(), *format, timeptr, &string,
&left,lc_time, alternate_form))
{
/* if we don't have any space left, do not set the failure flag:
* we will simply return ERANGE and do not call _invalid_parameter_handler
* (see below)
*/
if (left > 0)
{
failed=TRUE;
}
goto done;
}
format++; /* skip format char */
break;
default:
/* store character, bump pointers, dec the char count */
*string++ = *format++;
left--;
break;
}
}
/* All done. See if we terminated because we hit a null char or because
we ran out of space */
done:
if (!failed && left > 0) {
/* Store a terminating null char and return the number of chars
we stored in the output string. */
*string = L'\0';
return(maxsize-left);
}
else
{
/* error - return an empty string */
*(strstart) = L'\0';
/* now return our error/insufficient buffer indication */
if ( !failed && left <= 0 )
{
/* do not report this as an error to allow the caller to resize */
errno=ERANGE;
}
else
{
_VALIDATE_RETURN( FALSE, EINVAL, 0);
}
/* unused but compiler can't tell */
return 0;
}
}
extern "C" size_t __cdecl _Wcsftime (
wchar_t *string,
size_t maxsize,
const wchar_t *format,
const struct tm *timeptr,
void *lc_time_arg
)
{
return _Wcsftime_l(string, maxsize, format, timeptr,
lc_time_arg, NULL);
}
/* Some comments on the valid range of tm_year.
The check which ensures tm_year >= 0 should not be removed from:
asctime_s
asctime
_wasctime_s
_wasctime
these function did not handle well negative years in VS 2003 either;
17 Mar 1861 would be output as "Sun Mar 17 00:00:00 19-'".
The check which ensures tm_year >= 69 in the mktime family is correct;
we had the same check in VS 2003; we do not call _invalid_parameter in
this case, we simply return (-1) to indicate that mktime could not
transform from struct tm to time_t.
The check which ensures tm_year >= 0 in _W_expandtime("%y")
should not be removed (wcsftime calls _W_expandtime);
_W_expandtime("%y") did not handle well negative years in Everett either;
1861 would be printed out as "-'";
with _W_expandtime("%Y"), everything works well if tm_year >= -1900 && tm_year <= 8099.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -