]> Savannah Git Hosting - gnulib.git/commitdiff
mktime: refactor convert_time
authorPaul Eggert <eggert@cs.ucla.edu>
Fri, 4 Oct 2024 01:29:43 +0000 (18:29 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Fri, 4 Oct 2024 05:10:52 +0000 (22:10 -0700)
This is to better merge with a future version of glibc.
This merges a glibc patch by Florian Weimer in:
https://sourceware.org/pipermail/libc-alpha/2024-October/160308.html
* lib/mktime.c (convert_time): Accept a boolean flag instead
of a function pointer.  All callers changed.

ChangeLog
lib/mktime-internal.h
lib/mktime.c
lib/timegm.c

index 22a40c3d586b14e392eda61c7a5b6ddf646904cf..08a452130de26d71a90e37f3aeaeade8951d2608 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2024-10-03  Paul Eggert  <eggert@cs.ucla.edu>
+
+       mktime: refactor convert_time
+       This is to better merge with a future version of glibc.
+       This merges a glibc patch by Florian Weimer in:
+       https://sourceware.org/pipermail/libc-alpha/2024-October/160308.html
+       * lib/mktime.c (convert_time): Accept a boolean flag instead
+       of a function pointer.  All callers changed.
+
 2024-10-03  Bruno Haible  <bruno@clisp.org>
 
        bcp47: Add tests.
index 0693aaf14028c24ef6c31740f2b033cc9806e13f..3e2848c121042470a9c17e2426496b99231be659 100644 (file)
@@ -71,9 +71,8 @@ typedef int mktime_offset_t;
 #endif
 
 /* Subroutine of mktime.  Return the time_t representation of TP and
-   normalize TP, given that a struct tm * maps to a time_t as performed
-   by FUNC.  Record next guess for localtime-gmtime offset in *OFFSET.  */
-extern __time64_t __mktime_internal (struct tm *tp,
-                                     struct tm *(*func) (__time64_t const *,
-                                                         struct tm *),
+   normalize TP, given that a struct tm * maps to a time_t.  If
+   LOCAL, the mapping is performed by localtime_r, otherwise by gmtime_r.
+   Record next guess for localtime-gmtime offset in *OFFSET.  */
+extern __time64_t __mktime_internal (struct tm *tp, bool local,
                                      mktime_offset_t *offset) attribute_hidden;
index 744a7277bb4aef7f32e0a962cffffbd4bbf3511e..92ac9735b08576f2efa30b86e4f089ba400ab143 100644 (file)
@@ -251,29 +251,31 @@ tm_diff (long_int year, long_int yday, int hour, int min, int sec,
                     tp->tm_hour, tp->tm_min, tp->tm_sec);
 }
 
-/* Use CONVERT to convert T to a struct tm value in *TM.  T must be in
-   range for __time64_t.  Return TM if successful, NULL (setting errno) on
-   failure.  */
+/* Convert T to a struct tm value in *TM.  Use localtime64_r if LOCAL,
+   otherwise gmtime64_r.  T must be in range for __time64_t.  Return
+   TM if successful, NULL (setting errno) on failure.  */
 static struct tm *
-convert_time (struct tm *(*convert) (const __time64_t *, struct tm *),
-             long_int t, struct tm *tm)
+convert_time (bool local, long_int t, struct tm *tm)
 {
   __time64_t x = t;
-  return convert (&x, tm);
+  if (local)
+    return __localtime64_r (&x, tm);
+  else
+    return __gmtime64_r (&x, tm);
 }
 
-/* Use CONVERT to convert *T to a broken down time in *TP.
-   If *T is out of range for conversion, adjust it so that
-   it is the nearest in-range value and then convert that.
-   A value is in range if it fits in both __time64_t and long_int.
-   Return TP on success, NULL (setting errno) on failure.  */
+/* Convert *T to a broken down time in *TP (as if by localtime if
+   LOCAL, otherwise as if by gmtime).  If *T is out of range for
+   conversion, adjust it so that it is the nearest in-range value and
+   then convert that.  A value is in range if it fits in both
+   __time64_t and long_int.  Return TP on success, NULL (setting
+   errno) on failure.  */
 static struct tm *
-ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *),
-               long_int *t, struct tm *tp)
+ranged_convert (bool local, long_int *t, struct tm *tp)
 {
   long_int t1 = (*t < mktime_min ? mktime_min
                 : *t <= mktime_max ? *t : mktime_max);
-  struct tm *r = convert_time (convert, t1, tp);
+  struct tm *r = convert_time (local, t1, tp);
   if (r)
     {
       *t = t1;
@@ -294,7 +296,7 @@ ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *),
       long_int mid = long_int_avg (ok, bad);
       if (mid == ok || mid == bad)
        break;
-      if (convert_time (convert, mid, tp))
+      if (convert_time (local, mid, tp))
        ok = mid, oktm = *tp;
       else if (errno != EOVERFLOW)
        return NULL;
@@ -310,29 +312,28 @@ ranged_convert (struct tm *(*convert) (const __time64_t *, struct tm *),
 }
 
 
-/* Convert *TP to a __time64_t value, inverting
-   the monotonic and mostly-unit-linear conversion function CONVERT.
-   Use *OFFSET to keep track of a guess at the offset of the result,
+/* Convert *TP to a __time64_t value.  If LOCAL, the reverse mapping
+   is performed as if localtime, otherwise as if by gmtime.  Use
+   *OFFSET to keep track of a guess at the offset of the result,
    compared to what the result would be for UTC without leap seconds.
-   If *OFFSET's guess is correct, only one CONVERT call is needed.
-   If successful, set *TP to the canonicalized struct tm;
+   If *OFFSET's guess is correct, only one reverse mapping call is
+   needed.  If successful, set *TP to the canonicalized struct tm;
    otherwise leave *TP alone, return ((time_t) -1) and set errno.
    This function is external because it is used also by timegm.c.  */
 __time64_t
-__mktime_internal (struct tm *tp,
-                  struct tm *(*convert) (const __time64_t *, struct tm *),
-                  mktime_offset_t *offset)
+__mktime_internal (struct tm *tp, bool local, mktime_offset_t *offset)
 {
   struct tm tm;
 
-  /* The maximum number of probes (calls to CONVERT) should be enough
-     to handle any combinations of time zone rule changes, solar time,
-     leap seconds, and oscillations around a spring-forward gap.
-     POSIX.1 prohibits leap seconds, but some hosts have them anyway.  */
+  /* The maximum number of probes should be enough to handle any
+     combinations of time zone rule changes, solar time, leap seconds,
+     and oscillations around a spring-forward gap.  POSIX.1 prohibits
+     leap seconds, but some hosts have them anyway.  */
   int remaining_probes = 6;
 
-  /* Time requested.  Copy it in case CONVERT modifies *TP; this can
-     occur if TP is localtime's returned value and CONVERT is localtime.  */
+  /* Time requested.  Copy it in case gmtime/localtime modify *TP;
+     this can occur if TP is localtime's returned value and CONVERT is
+     localtime.  */
   int sec = tp->tm_sec;
   int min = tp->tm_min;
   int hour = tp->tm_hour;
@@ -390,7 +391,7 @@ __mktime_internal (struct tm *tp,
 
   while (true)
     {
-      if (! ranged_convert (convert, &t, &tm))
+      if (! ranged_convert (local, &t, &tm))
        return -1;
       long_int dt = tm_diff (year, yday, hour, min, sec, &tm);
       if (dt == 0)
@@ -469,7 +470,7 @@ __mktime_internal (struct tm *tp,
            if (! ckd_add (&ot, t, delta * direction))
              {
                struct tm otm;
-               if (! ranged_convert (convert, &ot, &otm))
+               if (! ranged_convert (local, &ot, &otm))
                  return -1;
                if (! isdst_differ (isdst, otm.tm_isdst))
                  {
@@ -479,7 +480,7 @@ __mktime_internal (struct tm *tp,
                                                &otm);
                    if (mktime_min <= gt && gt <= mktime_max)
                      {
-                       if (convert_time (convert, gt, &tm))
+                       if (convert_time (local, gt, &tm))
                          {
                            t = gt;
                            goto offset_found;
@@ -493,7 +494,7 @@ __mktime_internal (struct tm *tp,
 
       /* No unusual DST offset was found nearby.  Assume one-hour DST.  */
       t += 60 * 60 * dst_difference;
-      if (mktime_min <= t && t <= mktime_max && convert_time (convert, t, &tm))
+      if (mktime_min <= t && t <= mktime_max && convert_time (local, t, &tm))
        goto offset_found;
 
       __set_errno (EOVERFLOW);
@@ -520,7 +521,7 @@ __mktime_internal (struct tm *tp,
          __set_errno (EOVERFLOW);
          return -1;
        }
-      if (! convert_time (convert, t, &tm))
+      if (! convert_time (local, t, &tm))
        return -1;
     }
 
@@ -542,7 +543,7 @@ __mktime64 (struct tm *tp)
 
 # if defined _LIBC || NEED_MKTIME_WORKING
   static mktime_offset_t localtime_offset;
-  return __mktime_internal (tp, __localtime64_r, &localtime_offset);
+  return __mktime_internal (tp, true, &localtime_offset);
 # else
 #  undef mktime
   return mktime (tp);
index e5cf30c0198520caf5e6ca31df0f45f310122d90..1f1f66c61b84773937fea094dd3bf09d0c40c6c1 100644 (file)
@@ -31,7 +31,7 @@ __timegm64 (struct tm *tmp)
 {
   static mktime_offset_t gmtime_offset;
   tmp->tm_isdst = 0;
-  return __mktime_internal (tmp, __gmtime64_r, &gmtime_offset);
+  return __mktime_internal (tmp, false, &gmtime_offset);
 }
 
 #if defined _LIBC && __TIMESIZE != 64