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       |  58 ++++++++++++++
 5 files changed, 205 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 68dc2c50b294..521fe1cf9fc7 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -578,6 +578,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 \
@@ -643,6 +645,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 \
@@ -923,6 +926,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 487db673bcc3..3d3586042695 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..81b3421aa481
--- /dev/null
+++ b/mingw-w64-crt/misc/_mkgmtime64.c
@@ -0,0 +1,58 @@
+/**
+ * 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 "__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)
+{
+    unsigned long long value;
+    SYSTEMTIME systemtime;
+    FILETIME filetime;
+    __time64_t time64;
+
+    /*
+     * 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 */
+    value = (time64 * 10000000) + 116444736000000000LL;
+    filetime.dwLowDateTime = value & 0xffffffff;
+    filetime.dwHighDateTime = value >> 32;
+    if (!FileTimeToSystemTime(&filetime, &systemtime))
+        return -1;
+
+    /* 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 + 
((systemtime.wMonth >= 3 && ((systemtime.wYear % 4 == 0 && systemtime.wYear % 
100 != 0) || systemtime.wYear % 400 == 0)) ? 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
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to