Piotr Caban : msvcrt: Rewrite asctime function.
Alexandre Julliard
julliard at winehq.org
Wed Apr 11 12:56:47 CDT 2012
Module: wine
Branch: master
Commit: 0f7c834bd1cad6cf568d1fa758e956615ac68ad8
URL: http://source.winehq.org/git/wine.git/?a=commit;h=0f7c834bd1cad6cf568d1fa758e956615ac68ad8
Author: Piotr Caban <piotr at codeweavers.com>
Date: Wed Apr 11 15:21:32 2012 +0200
msvcrt: Rewrite asctime function.
---
dlls/msvcrt/msvcrt.h | 1 +
dlls/msvcrt/tests/time.c | 68 ++++++++++++++++++++++++++++++++++++++++++
dlls/msvcrt/time.c | 74 +++++++++++++++++++++++++++++-----------------
3 files changed, 116 insertions(+), 27 deletions(-)
diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h
index 6103c1e..26a1177 100644
--- a/dlls/msvcrt/msvcrt.h
+++ b/dlls/msvcrt/msvcrt.h
@@ -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);
diff --git a/dlls/msvcrt/tests/time.c b/dlls/msvcrt/tests/time.c
index a7790d5..16f8b9c 100644
--- a/dlls/msvcrt/tests/time.c
+++ b/dlls/msvcrt/tests/time.c
@@ -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();
}
diff --git a/dlls/msvcrt/time.c b/dlls/msvcrt/time.c
index f9de5c5..90dc790 100644
--- a/dlls/msvcrt/time.c
+++ b/dlls/msvcrt/time.c
@@ -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 );
- if (!data->asctime_buffer)
- data->asctime_buffer = MSVCRT_malloc( 30 ); /* ought to be enough */
+ /* 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;
+ }
+ }
-#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;
}
More information about the wine-cvs
mailing list