msvcrt: Implement _localtime64_s.
This commit is contained in:
parent
3c45bba11e
commit
e245cb52c6
|
@ -849,7 +849,7 @@
|
||||||
@ cdecl _localtime32(ptr) msvcrt._localtime32
|
@ cdecl _localtime32(ptr) msvcrt._localtime32
|
||||||
@ stub _localtime32_s
|
@ stub _localtime32_s
|
||||||
@ cdecl _localtime64(ptr) msvcrt._localtime64
|
@ cdecl _localtime64(ptr) msvcrt._localtime64
|
||||||
@ stub _localtime64_s
|
@ cdecl _localtime64_s(ptr ptr) msvcrt._localtime64_s
|
||||||
@ cdecl _lock(long) msvcrt._lock
|
@ cdecl _lock(long) msvcrt._lock
|
||||||
@ stub _lock_file
|
@ stub _lock_file
|
||||||
@ cdecl _locking(long long long) msvcrt._locking
|
@ cdecl _locking(long long long) msvcrt._locking
|
||||||
|
|
|
@ -695,7 +695,7 @@
|
||||||
@ cdecl _localtime32(ptr) msvcrt._localtime32
|
@ cdecl _localtime32(ptr) msvcrt._localtime32
|
||||||
@ stub _localtime32_s
|
@ stub _localtime32_s
|
||||||
@ cdecl _localtime64(ptr) msvcrt._localtime64
|
@ cdecl _localtime64(ptr) msvcrt._localtime64
|
||||||
@ stub _localtime64_s
|
@ cdecl _localtime64_s(ptr ptr) msvcrt._localtime64_s
|
||||||
@ cdecl _lock(long) msvcrt._lock
|
@ cdecl _lock(long) msvcrt._lock
|
||||||
@ stub _lock_file
|
@ stub _lock_file
|
||||||
@ cdecl _locking(long long long) msvcrt._locking
|
@ cdecl _locking(long long long) msvcrt._locking
|
||||||
|
|
|
@ -683,7 +683,7 @@
|
||||||
@ cdecl _localtime32(ptr) msvcrt._localtime32
|
@ cdecl _localtime32(ptr) msvcrt._localtime32
|
||||||
@ stub _localtime32_s
|
@ stub _localtime32_s
|
||||||
@ cdecl _localtime64(ptr) msvcrt._localtime64
|
@ cdecl _localtime64(ptr) msvcrt._localtime64
|
||||||
@ stub _localtime64_s
|
@ cdecl _localtime64_s(ptr ptr) msvcrt._localtime64_s
|
||||||
@ cdecl _lock(long) msvcrt._lock
|
@ cdecl _lock(long) msvcrt._lock
|
||||||
@ stub _lock_file
|
@ stub _lock_file
|
||||||
@ cdecl _locking(long long long) msvcrt._locking
|
@ cdecl _locking(long long long) msvcrt._locking
|
||||||
|
|
|
@ -717,6 +717,8 @@ typedef void (__cdecl *MSVCRT___sighandler_t)(int);
|
||||||
|
|
||||||
#define MSVCRT__TRUNCATE ((MSVCRT_size_t)-1)
|
#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_free(void*);
|
||||||
void* __cdecl MSVCRT_malloc(MSVCRT_size_t);
|
void* __cdecl MSVCRT_malloc(MSVCRT_size_t);
|
||||||
void* __cdecl MSVCRT_calloc(MSVCRT_size_t,MSVCRT_size_t);
|
void* __cdecl MSVCRT_calloc(MSVCRT_size_t,MSVCRT_size_t);
|
||||||
|
|
|
@ -622,7 +622,7 @@
|
||||||
@ cdecl _localtime32(ptr) MSVCRT__localtime32
|
@ cdecl _localtime32(ptr) MSVCRT__localtime32
|
||||||
# stub _localtime32_s
|
# stub _localtime32_s
|
||||||
@ cdecl _localtime64(ptr) MSVCRT__localtime64
|
@ cdecl _localtime64(ptr) MSVCRT__localtime64
|
||||||
# stub _localtime64_s
|
@ cdecl _localtime64_s(ptr ptr)
|
||||||
@ cdecl _lock(long)
|
@ cdecl _lock(long)
|
||||||
@ cdecl _locking(long long long) MSVCRT__locking
|
@ cdecl _locking(long long long) MSVCRT__locking
|
||||||
@ cdecl _logb( double )
|
@ cdecl _logb( double )
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#include <stdio.h> /*printf*/
|
#include <stdio.h> /*printf*/
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define _MAX__TIME64_T (((__time64_t)0x00000007 << 32) | 0x93406FFF)
|
||||||
|
|
||||||
#define SECSPERDAY 86400
|
#define SECSPERDAY 86400
|
||||||
#define SECSPERHOUR 3600
|
#define SECSPERHOUR 3600
|
||||||
#define SECSPERMIN 60
|
#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_gmtime32_s)(struct tm*, __time32_t*);
|
||||||
static errno_t (__cdecl *p_strtime_s)(char*,size_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_strdate_s)(char*,size_t);
|
||||||
|
static errno_t (__cdecl *p_localtime64_s)(struct tm*, __time64_t*);
|
||||||
|
|
||||||
static void init(void)
|
static void init(void)
|
||||||
{
|
{
|
||||||
|
@ -48,6 +51,7 @@ static void init(void)
|
||||||
p_mkgmtime32 = (void*)GetProcAddress(hmod, "_mkgmtime32");
|
p_mkgmtime32 = (void*)GetProcAddress(hmod, "_mkgmtime32");
|
||||||
p_strtime_s = (void*)GetProcAddress(hmod, "_strtime_s");
|
p_strtime_s = (void*)GetProcAddress(hmod, "_strtime_s");
|
||||||
p_strdate_s = (void*)GetProcAddress(hmod, "_strdate_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)
|
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);
|
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)
|
START_TEST(time)
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
|
@ -433,4 +502,5 @@ START_TEST(time)
|
||||||
test_strtime();
|
test_strtime();
|
||||||
test_wstrdate();
|
test_wstrdate();
|
||||||
test_wstrtime();
|
test_wstrtime();
|
||||||
|
test_localtime64_s();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
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
|
#define SECSPERDAY 86400
|
||||||
/* 1601 to 1970 is 369 years plus 89 leap days */
|
/* 1601 to 1970 is 369 years plus 89 leap days */
|
||||||
#define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
|
#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;
|
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.@)
|
* _localtime32 (MSVCRT.@)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -104,6 +104,7 @@ struct tm* __cdecl _gmtime32(const __time32_t*);
|
||||||
struct tm* __cdecl _gmtime64(const __time64_t*);
|
struct tm* __cdecl _gmtime64(const __time64_t*);
|
||||||
struct tm* __cdecl _localtime32(const __time32_t*);
|
struct tm* __cdecl _localtime32(const __time32_t*);
|
||||||
struct tm* __cdecl _localtime64(const __time64_t*);
|
struct tm* __cdecl _localtime64(const __time64_t*);
|
||||||
|
errno_t __cdecl _localtime64_s(struct tm*, const __time64_t*);
|
||||||
__time32_t __cdecl _mktime32(struct tm*);
|
__time32_t __cdecl _mktime32(struct tm*);
|
||||||
__time64_t __cdecl _mktime64(struct tm*);
|
__time64_t __cdecl _mktime64(struct tm*);
|
||||||
size_t __cdecl strftime(char*,size_t,const char*,const struct tm*);
|
size_t __cdecl strftime(char*,size_t,const char*,const struct tm*);
|
||||||
|
|
Loading…
Reference in New Issue