From e245cb52c6f4e2dd60a8e4989a2ba79e39039067 Mon Sep 17 00:00:00 2001 From: Andrew Nguyen Date: Mon, 11 Oct 2010 05:24:20 -0500 Subject: [PATCH] msvcrt: Implement _localtime64_s. --- dlls/msvcr100/msvcr100.spec | 2 +- dlls/msvcr80/msvcr80.spec | 2 +- dlls/msvcr90/msvcr90.spec | 2 +- dlls/msvcrt/msvcrt.h | 2 ++ dlls/msvcrt/msvcrt.spec | 2 +- dlls/msvcrt/tests/time.c | 70 +++++++++++++++++++++++++++++++++++++ dlls/msvcrt/time.c | 45 ++++++++++++++++++++++++ include/msvcrt/time.h | 1 + 8 files changed, 122 insertions(+), 4 deletions(-) diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec index 79517e50155..ace6201eeb9 100644 --- a/dlls/msvcr100/msvcr100.spec +++ b/dlls/msvcr100/msvcr100.spec @@ -849,7 +849,7 @@ @ cdecl _localtime32(ptr) msvcrt._localtime32 @ stub _localtime32_s @ cdecl _localtime64(ptr) msvcrt._localtime64 -@ stub _localtime64_s +@ cdecl _localtime64_s(ptr ptr) msvcrt._localtime64_s @ cdecl _lock(long) msvcrt._lock @ stub _lock_file @ cdecl _locking(long long long) msvcrt._locking diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec index 3795264a431..3c03f09ca4f 100644 --- a/dlls/msvcr80/msvcr80.spec +++ b/dlls/msvcr80/msvcr80.spec @@ -695,7 +695,7 @@ @ cdecl _localtime32(ptr) msvcrt._localtime32 @ stub _localtime32_s @ cdecl _localtime64(ptr) msvcrt._localtime64 -@ stub _localtime64_s +@ cdecl _localtime64_s(ptr ptr) msvcrt._localtime64_s @ cdecl _lock(long) msvcrt._lock @ stub _lock_file @ cdecl _locking(long long long) msvcrt._locking diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec index c0ed8b6dcc5..5917bccf146 100644 --- a/dlls/msvcr90/msvcr90.spec +++ b/dlls/msvcr90/msvcr90.spec @@ -683,7 +683,7 @@ @ cdecl _localtime32(ptr) msvcrt._localtime32 @ stub _localtime32_s @ cdecl _localtime64(ptr) msvcrt._localtime64 -@ stub _localtime64_s +@ cdecl _localtime64_s(ptr ptr) msvcrt._localtime64_s @ cdecl _lock(long) msvcrt._lock @ stub _lock_file @ cdecl _locking(long long long) msvcrt._locking diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h index 8e0bd43da2e..3d9639e3e28 100644 --- a/dlls/msvcrt/msvcrt.h +++ b/dlls/msvcrt/msvcrt.h @@ -717,6 +717,8 @@ typedef void (__cdecl *MSVCRT___sighandler_t)(int); #define MSVCRT__TRUNCATE ((MSVCRT_size_t)-1) +#define _MAX__TIME64_T (((MSVCRT___time64_t)0x00000007 << 32) | 0x93406FFF) + void __cdecl MSVCRT_free(void*); void* __cdecl MSVCRT_malloc(MSVCRT_size_t); void* __cdecl MSVCRT_calloc(MSVCRT_size_t,MSVCRT_size_t); diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec index 341093bea04..8f3a318b2f9 100644 --- a/dlls/msvcrt/msvcrt.spec +++ b/dlls/msvcrt/msvcrt.spec @@ -622,7 +622,7 @@ @ cdecl _localtime32(ptr) MSVCRT__localtime32 # stub _localtime32_s @ cdecl _localtime64(ptr) MSVCRT__localtime64 -# stub _localtime64_s +@ cdecl _localtime64_s(ptr ptr) @ cdecl _lock(long) @ cdecl _locking(long long long) MSVCRT__locking @ cdecl _logb( double ) diff --git a/dlls/msvcrt/tests/time.c b/dlls/msvcrt/tests/time.c index b11ecf7862b..38e06c20765 100644 --- a/dlls/msvcrt/tests/time.c +++ b/dlls/msvcrt/tests/time.c @@ -27,6 +27,8 @@ #include /*printf*/ #include +#define _MAX__TIME64_T (((__time64_t)0x00000007 << 32) | 0x93406FFF) + #define SECSPERDAY 86400 #define SECSPERHOUR 3600 #define SECSPERMIN 60 @@ -38,6 +40,7 @@ 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); +static errno_t (__cdecl *p_localtime64_s)(struct tm*, __time64_t*); static void init(void) { @@ -48,6 +51,7 @@ static void init(void) p_mkgmtime32 = (void*)GetProcAddress(hmod, "_mkgmtime32"); p_strtime_s = (void*)GetProcAddress(hmod, "_strtime_s"); p_strdate_s = (void*)GetProcAddress(hmod, "_strdate_s"); + p_localtime64_s = (void*)GetProcAddress(hmod, "_localtime64_s"); } static int get_test_year(time_t *start) @@ -421,6 +425,71 @@ static void test_wstrtime(void) ok(count == 3, "Wrong format: count = %d, should be 3\n", count); } +static void test_localtime64_s(void) +{ + struct tm tm; + __time64_t time; + errno_t err; + + if (!p_localtime64_s) + { + win_skip("Skipping _localtime64_s tests\n"); + return; + } + + errno = EBADF; + err = p_localtime64_s(NULL, NULL); + ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + + errno = EBADF; + time = 0xdeadbeef; + err = p_localtime64_s(NULL, &time); + ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + + memset(&tm, 0, sizeof(tm)); + errno = EBADF; + err = p_localtime64_s(&tm, NULL); + ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 && + tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 && + tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1, + "Expected tm structure members to be initialized to -1, got " + "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min, + tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday, + tm.tm_isdst); + + memset(&tm, 0, sizeof(tm)); + time = -1; + errno = EBADF; + err = p_localtime64_s(&tm, &time); + ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 && + tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 && + tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1, + "Expected tm structure members to be initialized to -1, got " + "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min, + tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday, + tm.tm_isdst); + + memset(&tm, 0, sizeof(tm)); + time = _MAX__TIME64_T + 1; + errno = EBADF; + err = p_localtime64_s(&tm, &time); + ok(err == EINVAL, "Expected _localtime64_s to return EINVAL, got %d\n", err); + ok(errno == EINVAL, "Expected errno to be EINVAL, got %d\n", errno); + ok(tm.tm_sec == -1 && tm.tm_min == -1 && tm.tm_hour == -1 && + tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1 && + tm.tm_wday == -1 && tm.tm_yday == -1 && tm.tm_isdst == -1, + "Expected tm structure members to be initialized to -1, got " + "(%d, %d, %d, %d, %d, %d, %d, %d, %d)\n", tm.tm_sec, tm.tm_min, + tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, tm.tm_wday, tm.tm_yday, + tm.tm_isdst); +} + START_TEST(time) { init(); @@ -433,4 +502,5 @@ START_TEST(time) test_strtime(); test_wstrdate(); test_wstrtime(); + test_localtime64_s(); } diff --git a/dlls/msvcrt/time.c b/dlls/msvcrt/time.c index df3159334a1..d0201e260cd 100644 --- a/dlls/msvcrt/time.c +++ b/dlls/msvcrt/time.c @@ -78,6 +78,19 @@ static inline void unix_tm_to_msvcrt( struct MSVCRT_tm *dest, const struct tm *s dest->tm_isdst = src->tm_isdst; } +static inline void write_invalid_msvcrt_tm( struct MSVCRT_tm *tm ) +{ + tm->tm_sec = -1; + tm->tm_min = -1; + tm->tm_hour = -1; + tm->tm_mday = -1; + tm->tm_mon = -1; + tm->tm_year = -1; + tm->tm_wday = -1; + tm->tm_yday = -1; + tm->tm_isdst = -1; +} + #define SECSPERDAY 86400 /* 1601 to 1970 is 369 years plus 89 leap days */ #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY) @@ -205,6 +218,38 @@ struct MSVCRT_tm* CDECL MSVCRT__localtime64(const MSVCRT___time64_t* secs) return &data->time_buffer; } +/********************************************************************* + * _localtime64_s (MSVCRT.@) + */ +int CDECL _localtime64_s(struct MSVCRT_tm *time, const MSVCRT___time64_t *secs) +{ + struct tm *tm; + time_t seconds; + + if (!time || !secs || *secs < 0 || *secs > _MAX__TIME64_T) + { + if (time) + write_invalid_msvcrt_tm(time); + + *MSVCRT__errno() = MSVCRT_EINVAL; + return MSVCRT_EINVAL; + } + + seconds = *secs; + + _mlock(_TIME_LOCK); + if (!(tm = localtime(&seconds))) + { + _munlock(_TIME_LOCK); + *MSVCRT__errno() = MSVCRT_EINVAL; + return MSVCRT_EINVAL; + } + + unix_tm_to_msvcrt(time, tm); + _munlock(_TIME_LOCK); + return 0; +} + /********************************************************************* * _localtime32 (MSVCRT.@) */ diff --git a/include/msvcrt/time.h b/include/msvcrt/time.h index ebbfbc248aa..194b47c2ca2 100644 --- a/include/msvcrt/time.h +++ b/include/msvcrt/time.h @@ -104,6 +104,7 @@ struct tm* __cdecl _gmtime32(const __time32_t*); struct tm* __cdecl _gmtime64(const __time64_t*); struct tm* __cdecl _localtime32(const __time32_t*); struct tm* __cdecl _localtime64(const __time64_t*); +errno_t __cdecl _localtime64_s(struct tm*, const __time64_t*); __time32_t __cdecl _mktime32(struct tm*); __time64_t __cdecl _mktime64(struct tm*); size_t __cdecl strftime(char*,size_t,const char*,const struct tm*);