diff src/memline.c @ 17135:d03a52e02f1a v8.1.1567

patch 8.1.1567: localtime_r() does not respond to $TZ changes commit https://github.com/vim/vim/commit/db51730df1817fc4b6ecf5a065c69fac518ad821 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Jun 18 22:53:24 2019 +0200 patch 8.1.1567: localtime_r() does not respond to $TZ changes Problem: Localtime_r() does not respond to $TZ changes. Solution: If $TZ changes then call tzset(). (Tom Ryder)
author Bram Moolenaar <Bram@vim.org>
date Tue, 18 Jun 2019 23:00:07 +0200
parents d5e1e09a829f
children 31f31e938961
line wrap: on
line diff
--- a/src/memline.c
+++ b/src/memline.c
@@ -2082,6 +2082,48 @@ get_b0_dict(char_u *fname, dict_T *d)
 #endif
 
 /*
+ * Cache of the current timezone name as retrieved from TZ, or an empty string
+ * where unset, up to 64 octets long including trailing null byte.
+ */
+#if defined(HAVE_LOCALTIME_R) && defined(HAVE_TZSET)
+static char	tz_cache[64];
+#endif
+
+/*
+ * Call either localtime(3) or localtime_r(3) from POSIX libc time.h, with the
+ * latter version preferred for reentrancy.
+ *
+ * If we use localtime_r(3) and we have tzset(3) available, check to see if the
+ * environment variable TZ has changed since the last run, and call tzset(3) to
+ * update the global timezone variables if it has.  This is because the POSIX
+ * standard doesn't require localtime_r(3) implementations to do that as it
+ * does with localtime(3), and we don't want to call tzset(3) every time.
+ */
+    struct tm *
+vim_localtime(
+    const time_t	*timep,		// timestamp for local representation
+    struct tm		*result)	// pointer to caller return buffer
+{
+#ifdef HAVE_LOCALTIME_R
+# ifdef HAVE_TZSET
+    char		*tz;		// pointer for TZ environment var
+
+    tz = (char *)mch_getenv((char_u *)"TZ");
+    if (tz == NULL)
+	tz = "";
+    if (STRNCMP(tz_cache, tz, sizeof(tz_cache) - 1) != 0)
+    {
+	tzset();
+	vim_strncpy((char_u *)tz_cache, (char_u *)tz, sizeof(tz_cache) - 1);
+    }
+# endif	// HAVE_TZSET
+    return localtime_r(timep, result);
+#else
+    return localtime(timep);
+#endif	// HAVE_LOCALTIME_R
+}
+
+/*
  * Replacement for ctime(), which is not safe to use.
  * Requires strftime(), otherwise returns "(unknown)".
  * If "thetime" is invalid returns "(invalid)".  Never returns NULL.
@@ -2093,16 +2135,10 @@ get_ctime(time_t thetime, int add_newlin
 {
     static char buf[50];
 #ifdef HAVE_STRFTIME
-# ifdef HAVE_LOCALTIME_R
     struct tm	tmval;
-# endif
     struct tm	*curtime;
 
-# ifdef HAVE_LOCALTIME_R
-    curtime = localtime_r(&thetime, &tmval);
-# else
-    curtime = localtime(&thetime);
-# endif
+    curtime = vim_localtime(&thetime, &tmval);
     /* MSVC returns NULL for an invalid value of seconds. */
     if (curtime == NULL)
 	vim_strncpy((char_u *)buf, (char_u *)_("(Invalid)"), sizeof(buf) - 1);