+/* 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. */
+static struct tm *
+ranged_convert (convert, t, tp)
+ struct tm *(*convert) __P ((const time_t *, struct tm *));
+ time_t *t;
+ struct tm *tp;
+{
+ struct tm *r;
+
+ if (! (r = (*convert) (t, tp)) && *t)
+ {
+ time_t bad = *t;
+ time_t ok = 0;
+ struct tm tm;
+
+ /* BAD is a known unconvertible time_t, and OK is a known good one.
+ Use binary search to narrow the range between BAD and OK until
+ they differ by 1. */
+ while (bad != ok + (bad < 0 ? -1 : 1))
+ {
+ time_t mid = *t = (bad < 0
+ ? bad + ((ok - bad) >> 1)
+ : ok + ((bad - ok) >> 1));
+ if ((r = (*convert) (t, tp)))
+ {
+ tm = *r;
+ ok = mid;
+ }
+ else
+ bad = mid;
+ }
+
+ if (!r && ok)
+ {
+ /* The last conversion attempt failed;
+ revert to the most recent successful attempt. */
+ *t = ok;
+ *tp = tm;
+ r = tp;
+ }
+ }
+
+ return r;
+}
+
+