Both functions are available since msvcr80.dll.
Additionally function _mkgmtime64 is available since Windows Server 2003
in system msvcrt.dll library (which predates first x64 version, which was
Windows Server 2003 SP1, and hence _mkgmtime64 is present in all x64 CRT
versions) and function _mkgmtime32 is available since Windows Vista in
system msvcrt.dll library.
For older CRT libraries provide emulation via musl libc __tm_to_secs()
function and normalization via WinAPI FileTimeToSystemTime() function.
We cannot use WinAPI SystemTimeToFileTime() function because it does not
work with invalid / not-normalized structure as opposite of the CRT
_mkgmtime function. Hence that is why the musl libc implementation is
included.
msvcrt _mkgmtime32() does not work for time before year 1970. Add similar
underflow checks into mingw-w64 emulation.
---
mingw-w64-crt/Makefile.am | 5 ++
mingw-w64-crt/lib-common/msvcrt.def.in | 6 +-
mingw-w64-crt/misc/__tm_to_secs.h | 104 +++++++++++++++++++++++++
mingw-w64-crt/misc/_mkgmtime32.c | 35 +++++++++
mingw-w64-crt/misc/_mkgmtime64.c | 61 +++++++++++++++
5 files changed, 208 insertions(+), 3 deletions(-)
create mode 100644 mingw-w64-crt/misc/__tm_to_secs.h
create mode 100644 mingw-w64-crt/misc/_mkgmtime32.c
create mode 100644 mingw-w64-crt/misc/_mkgmtime64.c
diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index 8ca36efd67cc..57a7efd91131 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -572,6 +572,8 @@ src_msvcrt32=\
misc/_get_fmode.c \
misc/_gmtime64.c \
misc/_initterm_e.c \
+ misc/_mkgmtime32.c \
+ misc/_mkgmtime64.c \
misc/_set_doserrno.c \
misc/_set_fmode.c \
misc/_time64.c \
@@ -637,6 +639,7 @@ src_msvcrt64=\
misc/_get_doserrno.c \
misc/_get_fmode.c \
misc/_initterm_e.c \
+ misc/_mkgmtime32.c \
misc/_set_doserrno.c \
misc/_set_fmode.c \
misc/output_format.c \
@@ -919,6 +922,8 @@ src_pre_msvcr80=\
misc/_invalid_parameter.c \
misc/_invalid_parameter_noinfo.c \
misc/_invoke_watson.c \
+ misc/_mkgmtime32.c \
+ misc/_mkgmtime64.c \
misc/_recalloc.c \
misc/_set_doserrno.c \
misc/_set_errno.c \
diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in
b/mingw-w64-crt/lib-common/msvcrt.def.in
index 02c7b64d604d..7ecdb11b2806 100644
--- a/mingw-w64-crt/lib-common/msvcrt.def.in
+++ b/mingw-w64-crt/lib-common/msvcrt.def.in
@@ -1237,8 +1237,8 @@ F_X86_ANY(__CxxFrameHandler2)
___lc_collate_cp_func
F_NON_I386(__pwctype_func) ; i386 __pwctype_func replaced by emu
F_NON_I386(_abs64) ; i386 _abs64 replaced by emu
-_mkgmtime
-_mkgmtime64
+F_NON_I386(_mkgmtime) ; i386 _mkgmtime replaced by emu
+F_NON_I386(_mkgmtime64) ; i386 _mkgmtime64 replaced by emu
F_NON_I386(_rotl64) ; i386 _rotl64 replaced by emu
F_NON_I386(_rotr64) ; i386 _rotr64 replaced by emu
_wctype DATA
@@ -1595,7 +1595,7 @@ _mbtowc_l
_mbsnlen
_mbstrnlen
_memicmp_l
-_mkgmtime32 F_I386(== _mkgmtime) ; i386 _mkgmtime32 replaced by alias
+F_ARM_ANY(_mkgmtime32) ; i386 and x64 _mkgmtime32 replaced by emu
F_ARM_ANY(_mktemp_s) ; i386 and x64 _mktemp_s replaced by emu
_mktime32 F_I386(== mktime) ; i386 _mktime32 replaced by alias
F_NON_I386(_msize_dbg)
diff --git a/mingw-w64-crt/misc/__tm_to_secs.h
b/mingw-w64-crt/misc/__tm_to_secs.h
new file mode 100644
index 000000000000..3c17c2d34012
--- /dev/null
+++ b/mingw-w64-crt/misc/__tm_to_secs.h
@@ -0,0 +1,104 @@
+/*
+ Copyright © 2005-2020 Rich Felker, et al.
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+static long long __year_to_secs(long long year, int *is_leap)
+{
+ if (year-2ULL <= 136) {
+ int y = year;
+ int leaps = (y-68)>>2;
+ if (!((y-68)&3)) {
+ leaps--;
+ if (is_leap) *is_leap = 1;
+ } else if (is_leap) *is_leap = 0;
+ return 31536000*(y-70) + 86400*leaps;
+ }
+
+ int cycles, centuries, leaps, rem, dummy;
+
+ if (!is_leap) is_leap = &dummy;
+ cycles = (year-100) / 400;
+ rem = (year-100) % 400;
+ if (rem < 0) {
+ cycles--;
+ rem += 400;
+ }
+ if (!rem) {
+ *is_leap = 1;
+ centuries = 0;
+ leaps = 0;
+ } else {
+ if (rem >= 200) {
+ if (rem >= 300) centuries = 3, rem -= 300;
+ else centuries = 2, rem -= 200;
+ } else {
+ if (rem >= 100) centuries = 1, rem -= 100;
+ else centuries = 0;
+ }
+ if (!rem) {
+ *is_leap = 0;
+ leaps = 0;
+ } else {
+ leaps = rem / 4U;
+ rem %= 4U;
+ *is_leap = !rem;
+ }
+ }
+
+ leaps += 97*cycles + 24*centuries - *is_leap;
+
+ return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400;
+}
+
+static int __month_to_secs(int month, int is_leap)
+{
+ static const int secs_through_month[] = {
+ 0, 31*86400, 59*86400, 90*86400,
+ 120*86400, 151*86400, 181*86400, 212*86400,
+ 243*86400, 273*86400, 304*86400, 334*86400 };
+ int t = secs_through_month[month];
+ if (is_leap && month >= 2) t+=86400;
+ return t;
+}
+
+static long long __tm_to_secs(const struct tm *tm)
+{
+ int is_leap;
+ long long year = tm->tm_year;
+ int month = tm->tm_mon;
+ if (month >= 12 || month < 0) {
+ int adj = month / 12;
+ month %= 12;
+ if (month < 0) {
+ adj--;
+ month += 12;
+ }
+ year += adj;
+ }
+ long long t = __year_to_secs(year, &is_leap);
+ t += __month_to_secs(month, is_leap);
+ t += 86400LL * (tm->tm_mday-1);
+ t += 3600LL * tm->tm_hour;
+ t += 60LL * tm->tm_min;
+ t += tm->tm_sec;
+ return t;
+}
diff --git a/mingw-w64-crt/misc/_mkgmtime32.c b/mingw-w64-crt/misc/_mkgmtime32.c
new file mode 100644
index 000000000000..71c12f86f4b5
--- /dev/null
+++ b/mingw-w64-crt/misc/_mkgmtime32.c
@@ -0,0 +1,35 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+
+#include <time.h>
+#include <stdint.h>
+
+static __time32_t __cdecl emu__mkgmtime32(struct tm *tmptr)
+{
+ struct tm tm64;
+ __time64_t time64;
+
+ tm64 = *tmptr;
+ time64 = _mkgmtime64(&tm64);
+
+ if (time64 == -1 || time64 < 0 || time64 > INT32_MAX)
+ return -1;
+
+ *tmptr = tm64;
+ return (__time32_t)time64;
+}
+
+#define RETT __time32_t
+#define FUNC _mkgmtime32
+#define ARGS struct tm *tmptr
+#define CALL tmptr
+#include "msvcrt_or_emu_glue.h"
+
+/* On 32-bit systems is _mkgmtime ABI using 32-bit time_t */
+#ifndef _WIN64
+time_t __attribute__((alias("_mkgmtime32"))) __cdecl _mkgmtime(struct tm
*tmptr);
+extern time_t
__attribute__((alias(__MINGW64_STRINGIFY(__MINGW_IMP_SYMBOL(_mkgmtime32)))))
(__cdecl *__MINGW_IMP_SYMBOL(_mkgmtime))(struct tm *tmptr);
+#endif
diff --git a/mingw-w64-crt/misc/_mkgmtime64.c b/mingw-w64-crt/misc/_mkgmtime64.c
new file mode 100644
index 000000000000..b17f05aa4924
--- /dev/null
+++ b/mingw-w64-crt/misc/_mkgmtime64.c
@@ -0,0 +1,61 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the mingw-w64 runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+
+#include <windows.h>
+#include <time.h>
+
+#include "filetime_to_time64.h"
+#include "__tm_to_secs.h"
+
+static const short int days_in_year[] = { -1, 30, 58, 89, 119, 150, 180, 211,
242, 272, 303, 333, 364 };
+
+static __time64_t __cdecl emu__mkgmtime64(struct tm *tmptr)
+{
+ SYSTEMTIME systemtime;
+ FILETIME filetime;
+ __time64_t time64;
+ int is_leap_year;
+ int has_leap_day;
+
+ /*
+ * WinAPI SystemTimeToFileTime() function is converting tm-like struct
+ * to timestamp but it accepts only SYSTEMTIME with valid wMilliseconds,
+ * wSecond, wMinute, wHour, wDay, wMonth, wYear values. CRT mkgmtime()
+ * accepts also struct tm with invalid tm_sec, tm_min, tm_hour, tm_mday,
+ * tm_mon, tm_year values and normalize them on return. So we cannot use
+ * WinAPI SystemTimeToFileTime() function for conversion. Instead includes
+ * and use the __tm_to_secs() function from the musl libc implementation.
+ */
+
+ time64 = __tm_to_secs(tmptr);
+
+ /* Convert the timestamp back to SYSTEMTIME for normalizing struct tm */
+ time64_to_filetime(time64, &filetime);
+ if (!FileTimeToSystemTime(&filetime, &systemtime))
+ return -1;
+
+ is_leap_year = ((systemtime.wYear % 4 == 0 && systemtime.wYear % 100 != 0)
|| systemtime.wYear % 400 == 0);
+ has_leap_day = (systemtime.wMonth >= 3 && is_leap_year);
+
+ /* Set back normalized values */
+ tmptr->tm_sec = systemtime.wSecond;
+ tmptr->tm_min = systemtime.wMinute;
+ tmptr->tm_hour = systemtime.wHour;
+ tmptr->tm_mday = systemtime.wDay;
+ tmptr->tm_mon = systemtime.wMonth - 1;
+ tmptr->tm_year = systemtime.wYear - 1900;
+ tmptr->tm_wday = systemtime.wDayOfWeek;
+ tmptr->tm_yday = days_in_year[tmptr->tm_mon] + systemtime.wDay +
(has_leap_day ? 1 : 0);
+ tmptr->tm_isdst = 0;
+
+ return time64;
+}
+
+#define RETT __time64_t
+#define FUNC _mkgmtime64
+#define ARGS struct tm *tmptr
+#define CALL tmptr
+#include "msvcrt_or_emu_glue.h"
--
2.20.1
_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public