bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] time_rz: port better to MinGW


From: Paul Eggert
Subject: [PATCH] time_rz: port better to MinGW
Date: Mon, 27 Jul 2015 16:42:26 -0700

Don't change tzname, as this makes MinGW dump core (Bug#21020).
Instead, store the tzname copy in the struct tm_zone object.
Problem reported by Eli Zaretskii in: http://bugs.gnu.org/21020#48
* lib/strftime.c [!_LIBC]:
* lib/time_rz.c: Include time-internal.h.
* lib/strftime.c (strftime_case_) [!HAVE_TM_ZONE]: Infer the zone
name from *TZ rather than from TZNAME, doable because *TZ now has
a tzname_copy member.
* lib/time-internal.h: New file, with contents taken from
lib/time_rz.c.  It's separate because strftime.c now accesses
struct tm_zone members.
(struct tm_zone) [HAVE_TZNAME && !HAVE_TM_ZONE]:
New member tzname_copy.
* lib/time_rz.c (struct tm_zone): Move to time-internal.h.
(tzalloc) [HAVE_TZNAME && !HAVE_TM_ZONE]:
Initialize tzname_copy member.
(save_abbr) [HAVE_TZNAME && !HAVE_TM_ZONE]: Save abbreviation
in tzname_copy member.
(revert_tz) [HAVE_TZNAME]: Remove no-longer-needed tzname saving.
(restore_tzname): Remove; no longer needed.  All calls removed.
* modules/time_rz (Files): Add lib/time-internal.h.
---
 ChangeLog           | 23 +++++++++++++
 lib/strftime.c      | 10 +++++-
 lib/time-internal.h | 49 +++++++++++++++++++++++++++
 lib/time_rz.c       | 98 +++++++++++++----------------------------------------
 modules/time_rz     |  1 +
 5 files changed, 106 insertions(+), 75 deletions(-)
 create mode 100644 lib/time-internal.h

diff --git a/ChangeLog b/ChangeLog
index 59a23d7..95b5a98 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,28 @@
 2015-07-27  Paul Eggert  <address@hidden>
 
+       time_rz: port better to MinGW
+       Don't change tzname, as this makes MinGW dump core (Bug#21020).
+       Instead, store the tzname copy in the struct tm_zone object.
+       Problem reported by Eli Zaretskii in: http://bugs.gnu.org/21020#48
+       * lib/strftime.c [!_LIBC]:
+       * lib/time_rz.c: Include time-internal.h.
+       * lib/strftime.c (strftime_case_) [!HAVE_TM_ZONE]: Infer the zone
+       name from *TZ rather than from TZNAME, doable because *TZ now has
+       a tzname_copy member.
+       * lib/time-internal.h: New file, with contents taken from
+       lib/time_rz.c.  It's separate because strftime.c now accesses
+       struct tm_zone members.
+       (struct tm_zone) [HAVE_TZNAME && !HAVE_TM_ZONE]:
+       New member tzname_copy.
+       * lib/time_rz.c (struct tm_zone): Move to time-internal.h.
+       (tzalloc) [HAVE_TZNAME && !HAVE_TM_ZONE]:
+       Initialize tzname_copy member.
+       (save_abbr) [HAVE_TZNAME && !HAVE_TM_ZONE]: Save abbreviation
+       in tzname_copy member.
+       (revert_tz) [HAVE_TZNAME]: Remove no-longer-needed tzname saving.
+       (restore_tzname): Remove; no longer needed.  All calls removed.
+       * modules/time_rz (Files): Add lib/time-internal.h.
+
        time: port __need_time_t to MinGW
        * lib/time.in.h (__need_time_t): Do not treat specially on MinGW.
        Fix reported by Eli Zaretskii in: http://bugs.gnu.org/21020#36
diff --git a/lib/strftime.c b/lib/strftime.c
index c7cec26..d1ca346 100644
--- a/lib/strftime.c
+++ b/lib/strftime.c
@@ -30,6 +30,7 @@
 # else
 #  include "strftime.h"
 # endif
+# include "time-internal.h"
 #endif
 
 #include <ctype.h>
@@ -440,6 +441,9 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
 # define am_len STRLEN (a_month)
 # define ap_len STRLEN (ampm)
 #endif
+#if HAVE_TZNAME
+  char **tzname_vec = tzname;
+#endif
   const char *zone;
   size_t i = 0;
   STREAM_OR_CHAR_T *p = s;
@@ -475,6 +479,10 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
     }
   else
     {
+# if !HAVE_TM_ZONE
+      /* Infer the zone name from *TZ instead of from TZNAME.  */
+      tzname_vec = tz->tzname_copy;
+# endif
       /* POSIX.1 requires that local time zone information be used as
          though strftime called tzset.  */
 # if HAVE_TZSET
@@ -483,7 +491,7 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
     }
   /* The tzset() call might have changed the value.  */
   if (!(zone && *zone) && tp->tm_isdst >= 0)
-    zone = tzname[tp->tm_isdst != 0];
+    zone = tzname_vec[tp->tm_isdst != 0];
 #endif
   if (! zone)
     zone = "";
diff --git a/lib/time-internal.h b/lib/time-internal.h
new file mode 100644
index 0000000..32f349f
--- /dev/null
+++ b/lib/time-internal.h
@@ -0,0 +1,49 @@
+/* Time internal interface
+
+   Copyright 2015 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Paul Eggert.  */
+
+/* A time zone rule.  */
+struct tm_zone
+{
+  /* More abbreviations, should they be needed.  Their TZ_IS_SET
+     members are zero.  */
+  struct tm_zone *next;
+
+#if HAVE_TZNAME && !HAVE_TM_ZONE
+  /* Copies of recent strings taken from tzname[0] and tzname[1].
+     The copies are in ABBRS, so that they survive tzset.  Null if unknown.  */
+  char *tzname_copy[2];
+#endif
+
+  /* If nonzero, the rule represents the TZ environment variable set
+     to the first "abbreviation" (this may be the empty string).
+     Otherwise, it represents an unset TZ.  */
+  char tz_is_set;
+
+  /* A sequence of null-terminated strings packed next to each other.
+     The strings are followed by an extra null byte.  If TZ_IS_SET,
+     there must be at least one string and the first string (which is
+     actually a TZ environment value value) may be empty.  Otherwise
+     all strings must be nonempty.
+
+     Abbreviations are stored here because otherwise the values of
+     tm_zone and/or tzname would be dead after changing TZ and calling
+     tzset.  Abbreviations never move once allocated, and are live
+     until tzfree is called.  */
+  char abbrs[FLEXIBLE_ARRAY_MEMBER];
+};
diff --git a/lib/time_rz.c b/lib/time_rz.c
index 142b2a1..d5c6dd5 100644
--- a/lib/time_rz.c
+++ b/lib/time_rz.c
@@ -32,35 +32,12 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "time-internal.h"
+
 #if !HAVE_TZSET
 static void tzset (void) { }
 #endif
 
-/* A time zone rule.  */
-struct tm_zone
-{
-  /* More abbreviations, should they be needed.  Their TZ_IS_SET
-     members are zero.  */
-  timezone_t next;
-
-  /* If nonzero, the rule represents the TZ environment variable set
-     to the first "abbreviation" (this may be the empty string).
-     Otherwise, it represents an unset TZ.  */
-  char tz_is_set;
-
-  /* A sequence of null-terminated strings packed next to each other.
-     The strings are followed by an extra null byte.  If TZ_IS_SET,
-     there must be at least one string and the first string (which is
-     actually a TZ environment value value) may be empty.  Otherwise
-     all strings must be nonempty.
-
-     Abbreviations are stored here because otherwise the values of
-     tm_zone and/or tzname would be dead after changing TZ and calling
-     tzset.  Abbreviations never move once allocated, and are live
-     until tzfree is called.  */
-  char abbrs[FLEXIBLE_ARRAY_MEMBER];
-};
-
 /* The approximate size to use for small allocation requests.  This is
    the largest "small" request for the GNU C library malloc.  */
 enum { DEFAULT_MXFAST = 64 * sizeof (size_t) / 4 };
@@ -124,39 +101,40 @@ tzalloc (char const *name)
   if (tz)
     {
       tz->next = NULL;
+#if HAVE_TZNAME && !HAVE_TM_ZONE
+      tz->tzname_copy[0] = tz->tzname_copy[1] = NULL;
+#endif
       tz->tz_is_set = !!name;
       extend_abbrs (tz->abbrs, name, name_size);
     }
   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 prepare to update tzname) if they use the abbreviation.
-   Return true if successful, false (setting errno) otherwise.  */
+/* Save into TZ any nontrivial time zone abbreviation used by TM, and
+   update *TM (if HAVE_TM_ZONE) or *TZ (if !HAVE_TM_ZONE &&
+   HAVE_TZNAME) if they use the abbreviation.  Return true if
+   successful, false (setting errno) otherwise.  */
 static bool
 save_abbr (timezone_t tz, struct tm *tm)
 {
 #if HAVE_TM_ZONE || HAVE_TZNAME
   char const *zone = NULL;
-  char **tzname_zone = NULL;
   char *zone_copy = (char *) "";
+
+# if HAVE_TZNAME
+  int tzname_index = -1;
+# endif
+
 # if HAVE_TM_ZONE
   zone = tm->tm_zone;
 # endif
+
 # if HAVE_TZNAME
   if (! (zone && *zone) && 0 <= tm->tm_isdst)
-    zone = *(tzname_zone = &tzname[0 < tm->tm_isdst]);
+    {
+      tzname_index = tm->tm_isdst != 0;
+      zone = tzname[tzname_index];
+    }
 # endif
 
   /* No need to replace null zones, or zones within the struct tm.  */
@@ -196,14 +174,13 @@ save_abbr (timezone_t tz, struct tm *tm)
 
   /* Replace the zone name so that its lifetime matches that of TZ.  */
 # if HAVE_TM_ZONE
-  if (!tzname_zone)
-    tm->tm_zone = zone_copy;
-# endif
-# if HAVE_TZNAME
-  tzname_address = tzname_zone;
-  tzname_value = zone_copy;
+  tm->tm_zone = zone_copy;
+# else
+  if (0 <= tzname_index)
+    tz->tzname_copy[tzname_index] = zone_copy;
 # endif
 #endif
+
   return true;
 }
 
@@ -292,41 +269,16 @@ revert_tz (timezone_t tz)
       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
@@ -348,8 +300,6 @@ localtime_rz (timezone_t tz, time_t const *t, struct tm *tm)
 time_t
 mktime_z (timezone_t tz, struct tm *tm)
 {
-  restore_tzname ();
-
   if (!tz)
     return timegm (tm);
   else
diff --git a/modules/time_rz b/modules/time_rz
index 97710b8..e934d55 100644
--- a/modules/time_rz
+++ b/modules/time_rz
@@ -13,6 +13,7 @@ the TZ environment variable to X.  tzalloc (NULL) is the same 
as an
 unset TZ environment variable.  (timezone_t) 0 stands for UTC.
 
 Files:
+lib/time-internal.h
 lib/time_rz.c
 m4/time_rz.m4
 
-- 
2.1.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]