changeset 18065:fd4663ad7454

time_rz: port to Solaris etc. Works around a tzname problem on platforms like Solaris that have tzname but not tm_zone, by setting tzname at the appropriate time and restoring it later. * lib/time_rz.c (tzname_address, tzname_value) [HAVE_TZNAME]: New static vars. (save_abbr) [HAVE_TZNAME]: Set them. (revert_tz) [HAVE_TZNAME]: Clear or use them. (restore_tzname): New function. (localtime_rz, mktime_z): Use it.
author Paul Eggert <eggert@cs.ucla.edu>
date Sat, 25 Jul 2015 15:20:10 -0700
parents e848c8248a0b
children fc4efc29b92e
files ChangeLog lib/time_rz.c
diffstat 2 files changed, 52 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
 2015-07-25  Paul Eggert  <eggert@cs.ucla.edu>
 
+	time_rz: port to Solaris etc.
+	Works around a tzname problem on platforms like Solaris that have
+	tzname but not tm_zone, by setting tzname at the appropriate time
+	and restoring it later.
+	* lib/time_rz.c (tzname_address, tzname_value) [HAVE_TZNAME]:
+	New static vars.
+	(save_abbr) [HAVE_TZNAME]: Set them.
+	(revert_tz) [HAVE_TZNAME]: Clear or use them.
+	(restore_tzname): New function.
+	(localtime_rz, mktime_z): Use it.
+
 	time_rz: now LGPL
 	* modules/time_rz (License): Now LGPL, because strftime depends on it.
 
--- a/lib/time_rz.c
+++ b/lib/time_rz.c
@@ -130,8 +130,19 @@
   return tz;
 }
 
+#if HAVE_TZNAME
+/* If TZNAME_ADDRESS is nonnull, an assignment of a saved abbreviation.
+   TZNAME_ADDRESS should be either null, or &tzname[0], or &tzname[1].
+   *TZNAME_ADDRESS = TZNAME_VALUE should be done after revert_tz
+   (indirectly) calls tzset, so that revert_tz can overwrite tzset's
+   assignment to tzname.  Also, it should be done at the start of
+   the next localtime_tz or mktime_z, to undo the overwrite.  */
+static char **tzname_address;
+static char *tzname_value;
+#endif
+
 /* Save into TZ any nontrivial time zone abbreviation used by TM,
-   and update *TM or tzname if they point to the abbreviation.
+   and update *TM (or prepare to update tzname) if they use the abbreviation.
    Return true if successful, false (setting errno) otherwise.  */
 static bool
 save_abbr (timezone_t tz, struct tm *tm)
@@ -189,8 +200,8 @@
     tm->tm_zone = zone_copy;
 # endif
 # if HAVE_TZNAME
-  if (tzname_zone)
-    *tzname_zone = zone_copy;
+  tzname_address = tzname_zone;
+  tzname_value = zone_copy;
 # endif
 #endif
   return true;
@@ -281,16 +292,41 @@
       bool ok = change_env (tz);
       if (!ok)
         saved_errno = errno;
+#if HAVE_TZNAME
+      if (!ok)
+        tzname_address = NULL;
+      if (tzname_address)
+        {
+          char *old_value = *tzname_address;
+          *tzname_address = tzname_value;
+          tzname_value = old_value;
+        }
+#endif
       tzfree (tz);
       errno = saved_errno;
       return ok;
     }
 }
 
+/* Restore an old tzname setting that was temporarily munged by revert_tz.  */
+static void
+restore_tzname (void)
+{
+#if HAVE_TZNAME
+  if (tzname_address)
+    {
+      *tzname_address = tzname_value;
+      tzname_address = NULL;
+    }
+#endif
+}
+
 /* Use time zone TZ to compute localtime_r (T, TM).  */
 struct tm *
 localtime_rz (timezone_t tz, time_t const *t, struct tm *tm)
 {
+  restore_tzname ();
+
   if (!tz)
     return gmtime_r (t, tm);
   else
@@ -312,6 +348,8 @@
 time_t
 mktime_z (timezone_t tz, struct tm *tm)
 {
+  restore_tzname ();
+
   if (!tz)
     return timegm (tm);
   else