msvcrt: Rewrite asctime function.
This commit is contained in:
parent
965388465d
commit
0f7c834bd1
|
@ -895,6 +895,7 @@ int __cdecl MSVCRT_vsnwprintf(MSVCRT_wchar_t *str, MSVCRT_size_t len,
|
|||
const MSVCRT_wchar_t *format, __ms_va_list valist );
|
||||
int __cdecl MSVCRT__snwprintf(MSVCRT_wchar_t*, unsigned int, const MSVCRT_wchar_t*, ...);
|
||||
int __cdecl MSVCRT_sprintf(char*,const char*,...);
|
||||
int __cdecl MSVCRT__snprintf(char*,unsigned int,const char*,...);
|
||||
int __cdecl MSVCRT__scprintf(const char*,...);
|
||||
int __cdecl MSVCRT_raise(int sig);
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ static int* (__cdecl *p__daylight)(void);
|
|||
static int* (__cdecl *p___p__daylight)(void);
|
||||
static size_t (__cdecl *p_strftime)(char *, size_t, const char *, const struct tm *);
|
||||
static size_t (__cdecl *p_wcsftime)(wchar_t *, size_t, const wchar_t *, const struct tm *);
|
||||
static char* (__cdecl *p_asctime)(const struct tm *);
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
|
@ -65,6 +66,7 @@ static void init(void)
|
|||
p___p__daylight = (void*)GetProcAddress(hmod, "__p__daylight");
|
||||
p_strftime = (void*)GetProcAddress(hmod, "strftime");
|
||||
p_wcsftime = (void*)GetProcAddress(hmod, "wcsftime");
|
||||
p_asctime = (void*)GetProcAddress(hmod, "asctime");
|
||||
}
|
||||
|
||||
static int get_test_year(time_t *start)
|
||||
|
@ -612,6 +614,71 @@ todo_wine
|
|||
ok(strcmp(bufA, buf) == 0, "expected %s, got %s\n", bufA, buf);
|
||||
}
|
||||
|
||||
static void test_asctime(void)
|
||||
{
|
||||
struct tm* gmt_tm;
|
||||
time_t gmt;
|
||||
char *ret;
|
||||
|
||||
if(!p_asctime || !p_gmtime)
|
||||
{
|
||||
win_skip("asctime or gmtime is not available\n");
|
||||
return;
|
||||
}
|
||||
|
||||
gmt = 0;
|
||||
gmt_tm = p_gmtime(&gmt);
|
||||
ret = p_asctime(gmt_tm);
|
||||
ok(!strcmp(ret, "Thu Jan 01 00:00:00 1970\n"), "asctime retunred %s\n", ret);
|
||||
|
||||
gmt = 312433121;
|
||||
gmt_tm = p_gmtime(&gmt);
|
||||
ret = p_asctime(gmt_tm);
|
||||
ok(!strcmp(ret, "Mon Nov 26 02:58:41 1979\n"), "asctime retunred %s\n", ret);
|
||||
|
||||
/* Week day is only checked if it's in 0..6 range */
|
||||
gmt_tm->tm_wday = 3;
|
||||
ret = p_asctime(gmt_tm);
|
||||
ok(!strcmp(ret, "Wed Nov 26 02:58:41 1979\n"), "asctime returned %s\n", ret);
|
||||
|
||||
errno = 0xdeadbeef;
|
||||
gmt_tm->tm_wday = 7;
|
||||
ret = p_asctime(gmt_tm);
|
||||
ok(!ret || broken(!ret[0]), "asctime returned %s\n", ret);
|
||||
ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno);
|
||||
|
||||
/* Year day is ignored */
|
||||
gmt_tm->tm_wday = 3;
|
||||
gmt_tm->tm_yday = 1300;
|
||||
ret = p_asctime(gmt_tm);
|
||||
ok(!strcmp(ret, "Wed Nov 26 02:58:41 1979\n"), "asctime returned %s\n", ret);
|
||||
|
||||
/* Dates that can't be displayed using 26 characters are broken */
|
||||
gmt_tm->tm_mday = 28;
|
||||
gmt_tm->tm_year = 8100;
|
||||
ret = p_asctime(gmt_tm);
|
||||
ok(!strcmp(ret, "Wed Nov 28 02:58:41 :000\n"), "asctime returned %s\n", ret);
|
||||
|
||||
gmt_tm->tm_year = 264100;
|
||||
ret = p_asctime(gmt_tm);
|
||||
ok(!strcmp(ret, "Wed Nov 28 02:58:41 :000\n"), "asctime returned %s\n", ret);
|
||||
|
||||
/* asctime works from year 1900 */
|
||||
errno = 0xdeadbeef;
|
||||
gmt_tm->tm_year = -1;
|
||||
ret = p_asctime(gmt_tm);
|
||||
ok(!ret || broken(!strcmp(ret, "Wed Nov 28 02:58:41 190/\n")), "asctime returned %s\n", ret);
|
||||
ok(errno==EINVAL || broken(errno == 0xdeadbeef), "errno = %d\n", errno);
|
||||
|
||||
errno = 0xdeadbeef;
|
||||
gmt_tm->tm_mon = 1;
|
||||
gmt_tm->tm_mday = 30;
|
||||
gmt_tm->tm_year = 79;
|
||||
ret = p_asctime(gmt_tm);
|
||||
ok(!ret || broken(!strcmp(ret, "Wed Feb 30 02:58:41 1979\n")), "asctime returned %s\n", ret);
|
||||
ok(errno==EINVAL || broken(errno==0xdeadbeef), "errno = %d\n", errno);
|
||||
}
|
||||
|
||||
START_TEST(time)
|
||||
{
|
||||
init();
|
||||
|
@ -628,4 +695,5 @@ START_TEST(time)
|
|||
test_localtime32_s();
|
||||
test_localtime64_s();
|
||||
test_daylight();
|
||||
test_asctime();
|
||||
}
|
||||
|
|
|
@ -877,30 +877,46 @@ MSVCRT_size_t CDECL MSVCRT_wcsftime( MSVCRT_wchar_t *str, MSVCRT_size_t max,
|
|||
return len;
|
||||
}
|
||||
|
||||
static char* asctime_buf(char *buf, const struct MSVCRT_tm *mstm)
|
||||
{
|
||||
static const char wday[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
||||
static const char month[12][4] = {"Jan", "Feb", "Mar", "Apr", "May",
|
||||
"Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||
|
||||
if (mstm->tm_sec<0 || mstm->tm_sec>59
|
||||
|| mstm->tm_min<0 || mstm->tm_min>59
|
||||
|| mstm->tm_hour<0 || mstm->tm_hour>23
|
||||
|| mstm->tm_mon<0 || mstm->tm_mon>11
|
||||
|| mstm->tm_wday<0 || mstm->tm_wday>6
|
||||
|| mstm->tm_year<0 || mstm->tm_mday<0
|
||||
|| mstm->tm_mday>MonthLengths[IsLeapYear(1900+mstm->tm_year)][mstm->tm_mon]) {
|
||||
*MSVCRT__errno() = MSVCRT_EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MSVCRT__snprintf(buf, 26, "%s %s %02d %02d:%02d:%02d %c%03d\n", wday[mstm->tm_wday],
|
||||
month[mstm->tm_mon], mstm->tm_mday, mstm->tm_hour, mstm->tm_min,
|
||||
mstm->tm_sec, '1'+(mstm->tm_year+900)/1000, (900+mstm->tm_year)%1000);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* asctime (MSVCRT.@)
|
||||
*/
|
||||
char * CDECL MSVCRT_asctime(const struct MSVCRT_tm *mstm)
|
||||
{
|
||||
char bufferA[30];
|
||||
WCHAR bufferW[30];
|
||||
|
||||
thread_data_t *data = msvcrt_get_thread_data();
|
||||
struct tm tm;
|
||||
|
||||
msvcrt_tm_to_unix( &tm, mstm );
|
||||
/* asctime returns date in format that always has exactly 26 characters */
|
||||
if (!data->asctime_buffer) {
|
||||
data->asctime_buffer = MSVCRT_malloc(26);
|
||||
if (!data->asctime_buffer) {
|
||||
*MSVCRT__errno() = MSVCRT_ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!data->asctime_buffer)
|
||||
data->asctime_buffer = MSVCRT_malloc( 30 ); /* ought to be enough */
|
||||
|
||||
#ifdef HAVE_ASCTIME_R
|
||||
asctime_r( &tm, bufferA );
|
||||
#else
|
||||
strcpy( bufferA, asctime(&tm) );
|
||||
#endif
|
||||
MultiByteToWideChar( CP_UNIXCP, 0, bufferA, -1, bufferW, 30 );
|
||||
WideCharToMultiByte( CP_ACP, 0, bufferW, -1, data->asctime_buffer, 30, NULL, NULL );
|
||||
return data->asctime_buffer;
|
||||
return asctime_buf(data->asctime_buffer, mstm);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
|
@ -908,23 +924,27 @@ char * CDECL MSVCRT_asctime(const struct MSVCRT_tm *mstm)
|
|||
*/
|
||||
int CDECL MSVCRT_asctime_s(char* time, MSVCRT_size_t size, const struct MSVCRT_tm *mstm)
|
||||
{
|
||||
char* asc;
|
||||
unsigned int len;
|
||||
|
||||
if (!MSVCRT_CHECK_PMT(time != NULL) || !MSVCRT_CHECK_PMT(mstm != NULL)) {
|
||||
if (!MSVCRT_CHECK_PMT(time != NULL)
|
||||
|| !MSVCRT_CHECK_PMT(mstm != NULL)
|
||||
|| !MSVCRT_CHECK_PMT(size >= 26)) {
|
||||
if (time && size)
|
||||
time[0] = 0;
|
||||
*MSVCRT__errno() = MSVCRT_EINVAL;
|
||||
return MSVCRT_EINVAL;
|
||||
}
|
||||
|
||||
asc = MSVCRT_asctime(mstm);
|
||||
len = strlen(asc) + 1;
|
||||
|
||||
if(!MSVCRT_CHECK_PMT(size >= len)) {
|
||||
*MSVCRT__errno() = MSVCRT_ERANGE;
|
||||
return MSVCRT_ERANGE;
|
||||
if (!MSVCRT_CHECK_PMT(mstm->tm_sec>=0) || !MSVCRT_CHECK_PMT(mstm->tm_sec<60)
|
||||
|| !MSVCRT_CHECK_PMT(mstm->tm_min>=0) || !MSVCRT_CHECK_PMT(mstm->tm_min<60)
|
||||
|| !MSVCRT_CHECK_PMT(mstm->tm_hour>=0) || !MSVCRT_CHECK_PMT(mstm->tm_hour<24)
|
||||
|| !MSVCRT_CHECK_PMT(mstm->tm_mon>=0) || !MSVCRT_CHECK_PMT(mstm->tm_mon<12)
|
||||
|| !MSVCRT_CHECK_PMT(mstm->tm_wday>=0) || !MSVCRT_CHECK_PMT(mstm->tm_wday<7)
|
||||
|| !MSVCRT_CHECK_PMT(mstm->tm_year>=0) || !MSVCRT_CHECK_PMT(mstm->tm_mday>=0)
|
||||
|| !MSVCRT_CHECK_PMT(mstm->tm_mday <= MonthLengths[IsLeapYear(1900+mstm->tm_year)][mstm->tm_mon])) {
|
||||
*MSVCRT__errno() = MSVCRT_EINVAL;
|
||||
return MSVCRT_EINVAL;
|
||||
}
|
||||
|
||||
strcpy(time, asc);
|
||||
asctime_buf(time, mstm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue