msvcrt: Rewrite asctime function.

This commit is contained in:
Piotr Caban 2012-04-11 15:21:32 +02:00 committed by Alexandre Julliard
parent 965388465d
commit 0f7c834bd1
3 changed files with 116 additions and 27 deletions

View File

@ -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);

View File

@ -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();
}

View File

@ -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;
}