/* 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 (struct tm *(*convert) (const time_t *, struct tm *), time_t *t, struct tm *tp) { struct tm *r = convert (t, tp); if (!r && *t) { time_t bad = *t; time_t ok = 0; /* 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 = time_t_avg(ok, bad); r = convert(t, tp); if (r) ok = mid; else bad = mid; } if (!r && ok) { /* The last conversion attempt failed; revert to the most recent successful attempt. */ *t = ok; r = convert(t, tp); } } return r; }
/* Return 1 if A + B does not overflow. If time_t is unsigned and if B's top bit is set, assume that the sum represents A - -B, and return 1 if the subtraction does not wrap around. */ static int time_t_add_ok(time_t a, time_t b) { if (! TYPE_SIGNED(time_t)) { time_t sum = (a + b); return ((sum < a) == (TIME_T_MIDPOINT <= b)); } else if (WRAPV) { time_t sum = (a + b); return ((sum < a) == (b < 0)); } else { time_t avg = time_t_avg(a, b); return (((TIME_T_MIN / 2) <= avg) && (avg <= (TIME_T_MAX / 2))); } }
/* Return 1 if A + B does not overflow. If time_t is unsigned and if B's top bit is set, assume that the sum represents A - -B, and return 1 if the subtraction does not wrap around. */ static int time_t_add_ok (time_t a, time_t b) { if (! TYPE_SIGNED (time_t)) { time_t sum = a + b; return (sum < a) == (TIME_T_MIDPOINT <= b); } else if (WRAPV) { time_t sum = a + b; return (sum < a) == (b < 0); } else { time_t avg = time_t_avg (a, b); return TIME_T_MIN / 2 <= avg && avg <= TIME_T_MAX / 2; } }