From: Paul Eggert Date: Mon, 27 Jul 2015 23:41:17 +0000 (-0700) Subject: time_rz: port better to MinGW X-Git-Tag: v1.0~6989 X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=d3bc69175327902b416f9bcde1cbc06793125a9a;p=gnulib.git 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. --- diff --git a/ChangeLog b/ChangeLog index 59a23d7a0b..95b5a9861c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,28 @@ 2015-07-27 Paul Eggert + 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 c7cec2621c..d1ca346b68 100644 --- a/lib/strftime.c +++ b/lib/strftime.c @@ -30,6 +30,7 @@ # else # include "strftime.h" # endif +# include "time-internal.h" #endif #include @@ -439,6 +440,9 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s, # define aw_len STRLEN (a_wkday) # 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; @@ -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 0000000000..32f349f322 --- /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 . */ + +/* 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 142b2a1503..d5c6dd52cc 100644 --- a/lib/time_rz.c +++ b/lib/time_rz.c @@ -32,35 +32,12 @@ #include #include +#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 97710b8c85..e934d55720 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