[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
mktime: add native Windows workaround
From: |
Bruno Haible |
Subject: |
mktime: add native Windows workaround |
Date: |
Sun, 30 Apr 2017 19:51:24 +0200 |
User-agent: |
KMail/5.1.3 (Linux/4.4.0-75-generic; KDE/5.18.0; x86_64; ; ) |
> * Some which should obey TZ, just that they should ignore the values set by
> Cygwin (instead of exhibiting garbage behaviour):
>
> mktime, _mktime*
> https://msdn.microsoft.com/en-us/library/d1y53h2a.aspx
> http://pubs.opengroup.org/onlinepubs/9699919799/functions/mktime.html
This patch adds the workaround against wrong interpretation of TZ on native
Windows to the 'mktime' function.
Also it fixes a three macrology problems:
- The use of module 'timegm' or 'mktime-internal' without module 'mktime'
could lead to a link error w.r.t. to symbol 'rpl_mktime' when the user
wants to use the mktime() function. (I think. Haven't checked.)
- The use of module 'mktime-internal' without module 'mktime' would still
define a function 'mktime' in mktime.o.
- When cross-compiling, it now prints "checking for working mktime...
guessing no"
instead of "checking for working mktime... no".
Ultimately, this macrology complexity is due to the fact that so much stuff
is contained in a single source file, lib/mktime.c. It would be simpler if
the mktime_internal function was a different compilation unit; then the
'mktime-internal' module could do AC_LIBOBJ([mktime-internal]) instead of
AC_LIBOBJ([mktime]).
2017-04-30 Bruno Haible <address@hidden>
mktime: Work around TZ problem on native Windows.
* lib/mktime.c: Add #ifs to make the algorithmic workaround independent
from the native Windows workaround.
* m4/mktime.m4 (gl_FUNC_MKTIME_WORKS): New macro, extracted from
gl_FUNC_MKTIME. If guessing, set gl_cv_func_working_mktime to
'guessing no'.
(gl_FUNC_MKTIME): Require it. Require AC_CANONICAL_HOST.
Set REPLACE_MKTIME to 1 on native Windows. Define NEED_MKTIME_WORKING,
NEED_MKTIME_WINDOWS.
(gl_FUNC_MKTIME_INTERNAL): Require gl_FUNC_MKTIME_WORKS, not
gl_FUNC_MKTIME. Set WANT_MKTIME_INTERNAL, not REPLACE_MKTIME. Define
NEED_MKTIME_INTERNAL.
* m4/timegm.m4 (gl_FUNC_TIMEGM): Require gl_FUNC_MKTIME_WORKS, not
gl_FUNC_MKTIME. Cope with 'guessing yes' value.
* modules/mktime-internal (configure.ac): Test WANT_MKTIME_INTERNAL,
not REPLACE_MKTIME.
* doc/posix-functions/mktime.texi: Mention the native Windows
workaround.
diff --git a/doc/posix-functions/mktime.texi b/doc/posix-functions/mktime.texi
index ffb7b79..35a9a41 100644
--- a/doc/posix-functions/mktime.texi
+++ b/doc/posix-functions/mktime.texi
@@ -9,6 +9,9 @@ Gnulib module: mktime
Portability problems fixed by Gnulib:
@itemize
@item
+On native Windows platforms (mingw, MSVC), this function works incorrectly
+when the environment variable @code{TZ} has been set by Cygwin.
address@hidden
@code{mktime} may go into an endless loop on some platforms.
@item
@code{mktime} may occasionally return wrong results on some platforms.
@@ -16,7 +19,4 @@ Portability problems fixed by Gnulib:
Portability problems not fixed by Gnulib:
@itemize
address@hidden
-On native Windows platforms (mingw, MSVC), this function works incorrectly
-when the environment variable @code{TZ} has been set by Cygwin.
@end itemize
diff --git a/lib/mktime.c b/lib/mktime.c
index 2efd44a..a78d960 100644
--- a/lib/mktime.c
+++ b/lib/mktime.c
@@ -23,6 +23,19 @@
# define DEBUG_MKTIME 0
#endif
+/* The following macros influence what gets defined when this file is compiled:
+
+ Macro/expression Which gnulib module This compilation unit
+ should define
+
+ NEED_MKTIME_WORKING mktime rpl_mktime
+ || NEED_MKTIME_WINDOWS
+
+ NEED_MKTIME_INTERNAL mktime-internal mktime_internal
+
+ DEBUG_MKTIME (defined manually) my_mktime, main
+ */
+
#if !defined _LIBC && !DEBUG_MKTIME
# include <config.h>
#endif
@@ -51,6 +64,13 @@
# define mktime my_mktime
#endif
+#if NEED_MKTIME_WINDOWS /* on native Windows */
+# include <stdlib.h>
+# include <string.h>
+#endif
+
+#if NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL || DEBUG_MKTIME
+
/* A signed type that can represent an integer number of years
multiplied by three times the number of seconds in a year. It is
needed when converting a tm_year value times the number of seconds
@@ -458,25 +478,46 @@ __mktime_internal (struct tm *tp,
return t;
}
+#endif /* NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL || DEBUG_MKTIME */
+
+#if NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS || DEBUG_MKTIME
+# if NEED_MKTIME_WORKING || DEBUG_MKTIME
static mktime_offset_t localtime_offset;
+# endif
/* Convert *TP to a time_t value. */
time_t
mktime (struct tm *tp)
{
-#ifdef _LIBC
+# if NEED_MKTIME_WINDOWS
+ /* If the environment variable TZ has been set by Cygwin, neutralize it.
+ The Microsoft CRT interprets TZ differently than Cygwin and produces
+ incorrect results if TZ has the syntax used by Cygwin. */
+ const char *tz = getenv ("TZ");
+ if (tz != NULL && strchr (tz, '/') != NULL)
+ _putenv ("TZ=");
+# endif
+
+# if NEED_MKTIME_WORKING || DEBUG_MKTIME
+# ifdef _LIBC
/* POSIX.1 8.1.1 requires that whenever mktime() is called, the
time zone names contained in the external variable 'tzname' shall
be set as if the tzset() function had been called. */
__tzset ();
-#elif HAVE_TZSET
+# elif HAVE_TZSET
tzset ();
-#endif
+# endif
return __mktime_internal (tp, __localtime_r, &localtime_offset);
+# else
+# undef mktime
+ return mktime (tp);
+# endif
}
+#endif /* NEED_MKTIME_WORKING || NEED_MKTIME_WINDOWS || DEBUG_MKTIME */
+
#ifdef weak_alias
weak_alias (mktime, timelocal)
#endif
diff --git a/m4/mktime.m4 b/m4/mktime.m4
index d594ddc..31da65e 100644
--- a/m4/mktime.m4
+++ b/m4/mktime.m4
@@ -1,4 +1,4 @@
-# serial 27
+# serial 28
dnl Copyright (C) 2002-2003, 2005-2007, 2009-2017 Free Software Foundation,
dnl Inc.
dnl This file is free software; the Free Software Foundation
@@ -21,9 +21,9 @@ AC_DEFUN([gl_TIME_T_IS_SIGNED],
fi
])
-AC_DEFUN([gl_FUNC_MKTIME],
+dnl Test whether mktime works. Set gl_cv_func_working_mktime.
+AC_DEFUN([gl_FUNC_MKTIME_WORKS],
[
- AC_REQUIRE([gl_HEADER_TIME_H_DEFAULTS])
AC_REQUIRE([gl_TIME_T_IS_SIGNED])
dnl We don't use AC_FUNC_MKTIME any more, because it is no longer maintained
@@ -239,29 +239,50 @@ main ()
}]])],
[gl_cv_func_working_mktime=yes],
[gl_cv_func_working_mktime=no],
- [gl_cv_func_working_mktime=no])
+ [gl_cv_func_working_mktime="guessing no"])
])
+])
+
+dnl Main macro of module 'mktime'.
+AC_DEFUN([gl_FUNC_MKTIME],
+[
+ AC_REQUIRE([gl_HEADER_TIME_H_DEFAULTS])
+ AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_REQUIRE([gl_FUNC_MKTIME_WORKS])
- if test $gl_cv_func_working_mktime = no; then
+ REPLACE_MKTIME=0
+ if test "$gl_cv_func_working_mktime" != yes; then
REPLACE_MKTIME=1
- else
- REPLACE_MKTIME=0
+ AC_DEFINE([NEED_MKTIME_WORKING], [1],
+ [Define if the compilation of mktime.c should define 'mktime'
+ with the algorithmic workarounds.])
fi
+ case "$host_os" in
+ mingw*)
+ REPLACE_MKTIME=1
+ AC_DEFINE([NEED_MKTIME_WINDOWS], [1],
+ [Define if the compilation of mktime.c should define 'mktime'
+ with the native Windows TZ workaround.])
+ ;;
+ esac
])
+dnl Main macro of module 'mktime-internal'.
AC_DEFUN([gl_FUNC_MKTIME_INTERNAL], [
- AC_REQUIRE([gl_FUNC_MKTIME])
- if test $REPLACE_MKTIME = 0; then
- dnl BeOS has __mktime_internal in libc, but other platforms don't.
- AC_CHECK_FUNC([__mktime_internal],
- [AC_DEFINE([mktime_internal], [__mktime_internal],
- [Define to the real name of the mktime_internal function.])
- ],
- [dnl mktime works but it doesn't export __mktime_internal,
- dnl so we need to substitute our own mktime implementation.
- REPLACE_MKTIME=1
- ])
- fi
+ AC_REQUIRE([gl_FUNC_MKTIME_WORKS])
+
+ WANT_MKTIME_INTERNAL=0
+ dnl BeOS has __mktime_internal in libc, but other platforms don't.
+ AC_CHECK_FUNC([__mktime_internal],
+ [AC_DEFINE([mktime_internal], [__mktime_internal],
+ [Define to the real name of the mktime_internal function.])
+ ],
+ [dnl mktime works but it doesn't export __mktime_internal,
+ dnl so we need to substitute our own mktime implementation.
+ WANT_MKTIME_INTERNAL=1
+ AC_DEFINE([NEED_MKTIME_INTERNAL], [1],
+ [Define if the compilation of mktime.c should define
'mktime_internal'.])
+ ])
])
# Prerequisites of lib/mktime.c.
diff --git a/m4/timegm.m4 b/m4/timegm.m4
index 510e25a..1f18552 100644
--- a/m4/timegm.m4
+++ b/m4/timegm.m4
@@ -1,4 +1,4 @@
-# timegm.m4 serial 11
+# timegm.m4 serial 12
dnl Copyright (C) 2003, 2007, 2009-2017 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
@@ -7,11 +7,11 @@ dnl with or without modifications, as long as this notice is
preserved.
AC_DEFUN([gl_FUNC_TIMEGM],
[
AC_REQUIRE([gl_HEADER_TIME_H_DEFAULTS])
- AC_REQUIRE([gl_FUNC_MKTIME])
+ AC_REQUIRE([gl_FUNC_MKTIME_WORKS])
REPLACE_TIMEGM=0
AC_CHECK_FUNCS_ONCE([timegm])
if test $ac_cv_func_timegm = yes; then
- if test $gl_cv_func_working_mktime = no; then
+ if test "$gl_cv_func_working_mktime" != yes; then
# Assume that timegm is buggy if mktime is.
REPLACE_TIMEGM=1
fi
diff --git a/modules/mktime-internal b/modules/mktime-internal
index f9cf460..1465c90 100644
--- a/modules/mktime-internal
+++ b/modules/mktime-internal
@@ -10,7 +10,7 @@ mktime
configure.ac:
gl_FUNC_MKTIME_INTERNAL
-if test $REPLACE_MKTIME = 1; then
+if test $WANT_MKTIME_INTERNAL = 1; then
AC_LIBOBJ([mktime])
gl_PREREQ_MKTIME
fi
- Re: what shall we do with the drunken time_t ?, (continued)
Re: what shall we do with the drunken time_t ?, Bruno Haible, 2017/04/29
- Re: what shall we do with the drunken time_t ?, Bruno Haible, 2017/04/30
- Re: what shall we do with the drunken time_t ?, Bruno Haible, 2017/04/30
- new module 'ctime', Bruno Haible, 2017/04/30
- new module 'localtime', Bruno Haible, 2017/04/30
- mktime: add native Windows workaround,
Bruno Haible <=
- new module 'strftime-fixes', Bruno Haible, 2017/04/30
- new module 'wcsftime', Bruno Haible, 2017/04/30