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