diff options
Diffstat (limited to 'lib/time_rz.c')
-rw-r--r-- | lib/time_rz.c | 81 |
1 files changed, 27 insertions, 54 deletions
diff --git a/lib/time_rz.c b/lib/time_rz.c index b1b944af782..3ac053c6219 100644 --- a/lib/time_rz.c +++ b/lib/time_rz.c @@ -27,19 +27,15 @@ #include <time.h> #include <errno.h> -#include <limits.h> #include <stdbool.h> #include <stddef.h> #include <stdlib.h> #include <string.h> #include "flexmember.h" +#include "idx.h" #include "time-internal.h" -#ifndef SIZE_MAX -# define SIZE_MAX ((size_t) -1) -#endif - /* 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 }; @@ -54,31 +50,6 @@ enum { ABBR_SIZE_MIN = DEFAULT_MXFAST - offsetof (struct tm_zone, abbrs) }; matters; the pointer is never dereferenced. */ static timezone_t const local_tz = (timezone_t) 1; -#if HAVE_TM_ZONE || HAVE_TZNAME - -/* Return true if the values A and B differ according to the rules for - tm_isdst: A and B differ if one is zero and the other positive. */ -static bool -isdst_differ (int a, int b) -{ - return !a != !b && 0 <= a && 0 <= b; -} - -/* Return true if A and B are equal. */ -static int -equal_tm (const struct tm *a, const struct tm *b) -{ - return ! ((a->tm_sec ^ b->tm_sec) - | (a->tm_min ^ b->tm_min) - | (a->tm_hour ^ b->tm_hour) - | (a->tm_mday ^ b->tm_mday) - | (a->tm_mon ^ b->tm_mon) - | (a->tm_year ^ b->tm_year) - | isdst_differ (a->tm_isdst, b->tm_isdst)); -} - -#endif - /* Copy to ABBRS the abbreviation at ABBR with size ABBR_SIZE (this includes its trailing null byte). Append an extra null byte to mark the end of ABBRS. */ @@ -100,7 +71,7 @@ tzalloc (char const *name) if (tz) { tz->next = NULL; -#if HAVE_TZNAME && !HAVE_TM_ZONE +#if HAVE_TZNAME && !HAVE_STRUCT_TM_TM_ZONE tz->tzname_copy[0] = tz->tzname_copy[1] = NULL; #endif tz->tz_is_set = !!name; @@ -112,13 +83,13 @@ tzalloc (char const *name) } /* 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. */ + update *TM (if HAVE_STRUCT_TM_TM_ZONE) or *TZ (if + !HAVE_STRUCT_TM_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 +#if HAVE_STRUCT_TM_TM_ZONE || HAVE_TZNAME char const *zone = NULL; char *zone_copy = (char *) ""; @@ -126,7 +97,7 @@ save_abbr (timezone_t tz, struct tm *tm) int tzname_index = -1; # endif -# if HAVE_TM_ZONE +# if HAVE_STRUCT_TM_TM_ZONE zone = tm->tm_zone; # endif @@ -150,14 +121,8 @@ save_abbr (timezone_t tz, struct tm *tm) { if (! (*zone_copy || (zone_copy == tz->abbrs && tz->tz_is_set))) { - size_t zone_size = strlen (zone) + 1; - size_t zone_used = zone_copy - tz->abbrs; - if (SIZE_MAX - zone_used < zone_size) - { - errno = ENOMEM; - return false; - } - if (zone_used + zone_size < ABBR_SIZE_MIN) + idx_t zone_size = strlen (zone) + 1; + if (zone_size < tz->abbrs + ABBR_SIZE_MIN - zone_copy) extend_abbrs (zone_copy, zone, zone_size); else { @@ -180,7 +145,7 @@ 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 HAVE_STRUCT_TM_TM_ZONE tm->tm_zone = zone_copy; # else if (0 <= tzname_index) @@ -327,17 +292,25 @@ mktime_z (timezone_t tz, struct tm *tm) timezone_t old_tz = set_tz (tz); if (old_tz) { - time_t t = mktime (tm); -#if HAVE_TM_ZONE || HAVE_TZNAME - time_t badtime = -1; struct tm tm_1; - if ((t != badtime - || (localtime_r (&t, &tm_1) && equal_tm (tm, &tm_1))) - && !save_abbr (tz, tm)) - t = badtime; + tm_1.tm_sec = tm->tm_sec; + tm_1.tm_min = tm->tm_min; + tm_1.tm_hour = tm->tm_hour; + tm_1.tm_mday = tm->tm_mday; + tm_1.tm_mon = tm->tm_mon; + tm_1.tm_year = tm->tm_year; + tm_1.tm_yday = -1; + tm_1.tm_isdst = tm->tm_isdst; + time_t t = mktime (&tm_1); + bool ok = 0 <= tm_1.tm_yday; +#if HAVE_STRUCT_TM_TM_ZONE || HAVE_TZNAME + ok = ok && save_abbr (tz, &tm_1); #endif - if (revert_tz (old_tz)) - return t; + if (revert_tz (old_tz) && ok) + { + *tm = tm_1; + return t; + } } return -1; } |