diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec index a6b8ec026cd..5e8680b6f01 100644 --- a/dlls/msvcr100/msvcr100.spec +++ b/dlls/msvcr100/msvcr100.spec @@ -719,9 +719,9 @@ @ stub _getws_s @ cdecl -i386 _global_unwind2(ptr) msvcrt._global_unwind2 @ cdecl _gmtime32(ptr) msvcrt._gmtime32 -@ stub _gmtime32_s +@ cdecl _gmtime32_s(ptr ptr) msvcrt._gmtime32_s @ cdecl _gmtime64(ptr) msvcrt._gmtime64 -@ stub _gmtime64_s +@ cdecl _gmtime64_s(ptr ptr) msvcrt._gmtime64_s @ cdecl _heapadd(ptr long) msvcrt._heapadd @ cdecl _heapchk() msvcrt._heapchk @ cdecl _heapmin() msvcrt._heapmin diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec index ae2a1f8e65a..f47bd83f757 100644 --- a/dlls/msvcr80/msvcr80.spec +++ b/dlls/msvcr80/msvcr80.spec @@ -566,9 +566,9 @@ @ stub _getws_s @ cdecl -i386 _global_unwind2(ptr) msvcrt._global_unwind2 @ cdecl _gmtime32(ptr) msvcrt._gmtime32 -@ stub _gmtime32_s +@ cdecl _gmtime32_s(ptr ptr) msvcrt._gmtime32_s @ cdecl _gmtime64(ptr) msvcrt._gmtime64 -@ stub _gmtime64_s +@ cdecl _gmtime64_s(ptr ptr) msvcrt._gmtime64_s @ cdecl _heapadd(ptr long) msvcrt._heapadd @ cdecl _heapchk() msvcrt._heapchk @ cdecl _heapmin() msvcrt._heapmin diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec index 7000c2d6d46..fbe5458b5f9 100644 --- a/dlls/msvcr90/msvcr90.spec +++ b/dlls/msvcr90/msvcr90.spec @@ -554,9 +554,9 @@ @ stub _getws_s @ cdecl -i386 _global_unwind2(ptr) msvcrt._global_unwind2 @ cdecl _gmtime32(ptr) msvcrt._gmtime32 -@ stub _gmtime32_s +@ cdecl _gmtime32_s(ptr ptr) msvcrt._gmtime32_s @ cdecl _gmtime64(ptr) msvcrt._gmtime64 -@ stub _gmtime64_s +@ cdecl _gmtime64_s(ptr ptr) msvcrt._gmtime64_s @ cdecl _heapadd(ptr long) msvcrt._heapadd @ cdecl _heapchk() msvcrt._heapchk @ cdecl _heapmin() msvcrt._heapmin diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec index 2ace243e901..93bbfd720b9 100644 --- a/dlls/msvcrt/msvcrt.spec +++ b/dlls/msvcrt/msvcrt.spec @@ -499,9 +499,9 @@ @ cdecl _getws(ptr) MSVCRT__getws @ cdecl -i386 _global_unwind2(ptr) @ cdecl _gmtime32(ptr) MSVCRT__gmtime32 -# stub _gmtime32_s +@ cdecl _gmtime32_s(ptr ptr) MSVCRT__gmtime32_s @ cdecl _gmtime64(ptr) MSVCRT__gmtime64 -# stub _gmtime64_s +@ cdecl _gmtime64_s(ptr ptr) MSVCRT__gmtime64_s @ cdecl _heapadd (ptr long) @ cdecl _heapchk() @ cdecl _heapmin() diff --git a/dlls/msvcrt/tests/time.c b/dlls/msvcrt/tests/time.c index 78d8e094962..b11ecf7862b 100644 --- a/dlls/msvcrt/tests/time.c +++ b/dlls/msvcrt/tests/time.c @@ -35,6 +35,7 @@ static __time32_t (__cdecl *p_mkgmtime32)(struct tm*); static struct tm* (__cdecl *p_gmtime32)(__time32_t*); +static errno_t (__cdecl *p_gmtime32_s)(struct tm*, __time32_t*); static errno_t (__cdecl *p_strtime_s)(char*,size_t); static errno_t (__cdecl *p_strdate_s)(char*,size_t); @@ -43,6 +44,7 @@ static void init(void) HMODULE hmod = GetModuleHandleA("msvcrt.dll"); p_gmtime32 = (void*)GetProcAddress(hmod, "_gmtime32"); + p_gmtime32_s = (void*)GetProcAddress(hmod, "_gmtime32_s"); p_mkgmtime32 = (void*)GetProcAddress(hmod, "_mkgmtime32"); p_strtime_s = (void*)GetProcAddress(hmod, "_strtime_s"); p_strdate_s = (void*)GetProcAddress(hmod, "_strdate_s"); @@ -71,13 +73,21 @@ static void test_ctime(void) static void test_gmtime(void) { __time32_t valid, gmt; - struct tm* gmt_tm; + struct tm* gmt_tm, gmt_tm_s; + errno_t err; if(!p_gmtime32) { win_skip("Skipping _gmtime32 tests\n"); return; } + gmt_tm = p_gmtime32(NULL); + ok(gmt_tm == NULL, "gmt_tm != NULL\n"); + + gmt = -1; + gmt_tm = p_gmtime32(&gmt); + ok(gmt_tm == NULL, "gmt_tm != NULL\n"); + gmt = valid = 0; gmt_tm = p_gmtime32(&gmt); if(!gmt_tm) { @@ -133,6 +143,24 @@ static void test_gmtime(void) gmt_tm->tm_isdst = 1; gmt = p_mkgmtime32(gmt_tm); ok(gmt == valid, "gmt = %u\n", gmt); + + if(!p_gmtime32_s) { + win_skip("Skipping _gmtime32_s tests\n"); + return; + } + + errno = 0; + gmt = 0; + err = p_gmtime32_s(NULL, &gmt); + ok(err == EINVAL, "err = %d\n", err); + ok(errno == EINVAL, "errno = %d\n", errno); + + errno = 0; + gmt = -1; + err = p_gmtime32_s(&gmt_tm_s, &gmt); + ok(err == EINVAL, "err = %d\n", err); + ok(errno == EINVAL, "errno = %d\n", errno); + ok(gmt_tm_s.tm_year == -1, "tm_year = %d\n", gmt_tm_s.tm_year); } static void test_mktime(void) diff --git a/dlls/msvcrt/time.c b/dlls/msvcrt/time.c index 50442036685..54bbd74761d 100644 --- a/dlls/msvcrt/time.c +++ b/dlls/msvcrt/time.c @@ -232,37 +232,78 @@ struct MSVCRT_tm* CDECL MSVCRT_localtime(const MSVCRT___time32_t* secs) /********************************************************************* * _gmtime64 (MSVCRT.@) */ -struct MSVCRT_tm* CDECL MSVCRT__gmtime64(const MSVCRT___time64_t* secs) +int CDECL MSVCRT__gmtime64_s(struct MSVCRT_tm *res, const MSVCRT___time64_t *secs) { - thread_data_t * const data = msvcrt_get_thread_data(); - int i; - FILETIME ft; - SYSTEMTIME st; + int i; + FILETIME ft; + SYSTEMTIME st; + ULONGLONG time; - ULONGLONG time = *secs * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970; + if(!res || !secs || *secs<0) { + if(res) { + res->tm_sec = -1; + res->tm_min = -1; + res->tm_hour = -1; + res->tm_mday = -1; + res->tm_year = -1; + res->tm_mon = -1; + res->tm_wday = -1; + res->tm_yday = -1; + res->tm_isdst = -1; + } - ft.dwHighDateTime = (UINT)(time >> 32); - ft.dwLowDateTime = (UINT)time; + *MSVCRT__errno() = MSVCRT_EINVAL; + return MSVCRT_EINVAL; + } - FileTimeToSystemTime(&ft, &st); + time = *secs * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970; - if (st.wYear < 1970) return NULL; + ft.dwHighDateTime = (UINT)(time >> 32); + ft.dwLowDateTime = (UINT)time; - data->time_buffer.tm_sec = st.wSecond; - data->time_buffer.tm_min = st.wMinute; - data->time_buffer.tm_hour = st.wHour; - data->time_buffer.tm_mday = st.wDay; - data->time_buffer.tm_year = st.wYear - 1900; - data->time_buffer.tm_mon = st.wMonth - 1; - data->time_buffer.tm_wday = st.wDayOfWeek; - for (i = data->time_buffer.tm_yday = 0; i < st.wMonth - 1; i++) { - data->time_buffer.tm_yday += MonthLengths[IsLeapYear(st.wYear)][i]; - } + FileTimeToSystemTime(&ft, &st); - data->time_buffer.tm_yday += st.wDay - 1; - data->time_buffer.tm_isdst = 0; + res->tm_sec = st.wSecond; + res->tm_min = st.wMinute; + res->tm_hour = st.wHour; + res->tm_mday = st.wDay; + res->tm_year = st.wYear - 1900; + res->tm_mon = st.wMonth - 1; + res->tm_wday = st.wDayOfWeek; + for (i = res->tm_yday = 0; i < st.wMonth - 1; i++) { + res->tm_yday += MonthLengths[IsLeapYear(st.wYear)][i]; + } - return &data->time_buffer; + res->tm_yday += st.wDay - 1; + res->tm_isdst = 0; + + return 0; +} + +/********************************************************************* + * _gmtime64 (MSVCRT.@) + */ +struct MSVCRT_tm* CDECL MSVCRT__gmtime64(const MSVCRT___time64_t *secs) +{ + thread_data_t * const data = msvcrt_get_thread_data(); + + if(MSVCRT__gmtime64_s(&data->time_buffer, secs)) + return NULL; + return &data->time_buffer; +} + +/********************************************************************* + * _gmtime32_s (MSVCRT.@) + */ +int CDECL MSVCRT__gmtime32_s(struct MSVCRT_tm *res, const MSVCRT___time32_t *secs) +{ + MSVCRT___time64_t secs64; + + if(secs) { + secs64 = *secs; + return MSVCRT__gmtime64_s(res, &secs64); + } + return MSVCRT__gmtime64_s(res, NULL); } /********************************************************************* @@ -270,7 +311,12 @@ struct MSVCRT_tm* CDECL MSVCRT__gmtime64(const MSVCRT___time64_t* secs) */ struct MSVCRT_tm* CDECL MSVCRT__gmtime32(const MSVCRT___time32_t* secs) { - MSVCRT___time64_t secs64 = *secs; + MSVCRT___time64_t secs64; + + if(!secs) + return NULL; + + secs64 = *secs; return MSVCRT__gmtime64( &secs64 ); }