aboutsummaryrefslogtreecommitdiffstats
path: root/lib/mktime.c
diff options
context:
space:
mode:
authorPaul Eggert2018-11-16 08:24:54 -0800
committerPaul Eggert2018-11-16 08:25:27 -0800
commit7382f64bd074de59b30c88dd4056186645085a2e (patch)
treeda6d0410036aed0515484baca81981eb660da9ca /lib/mktime.c
parentf7cbe83e3b37d2faa56947490e8eaa348565b1af (diff)
downloademacs-7382f64bd074de59b30c88dd4056186645085a2e.tar.gz
emacs-7382f64bd074de59b30c88dd4056186645085a2e.zip
Update from glibc and Gnulib
This incorporates: 2018-11-15 mktime: DEBUG_MKTIME cleanup 2018-11-15 mktime: fix non-EOVERFLOW errno handling 2018-11-15 mktime: fix bug with Y2038 DST transition 2018-11-15 mktime: make more room for overflow 2018-11-15 mktime: simplify offset guess 2018-11-15 mktime: new test for mktime failure 2018-11-15 mktime: fix EOVERFLOW bug 2018-11-13 longlong: fix comment typo * lib/gnulib.mk.in: Regenerate. * lib/mktime.c, m4/longlong.m4: Copy from Gnulib.
Diffstat (limited to 'lib/mktime.c')
-rw-r--r--lib/mktime.c391
1 files changed, 125 insertions, 266 deletions
diff --git a/lib/mktime.c b/lib/mktime.c
index 557712fdaa4..9c3fb20f79d 100644
--- a/lib/mktime.c
+++ b/lib/mktime.c
@@ -17,12 +17,6 @@
17 License along with the GNU C Library; if not, see 17 License along with the GNU C Library; if not, see
18 <https://www.gnu.org/licenses/>. */ 18 <https://www.gnu.org/licenses/>. */
19 19
20/* Define this to 1 to have a standalone program to test this implementation of
21 mktime. */
22#ifndef DEBUG_MKTIME
23# define DEBUG_MKTIME 0
24#endif
25
26/* The following macros influence what gets defined when this file is compiled: 20/* The following macros influence what gets defined when this file is compiled:
27 21
28 Macro/expression Which gnulib module This compilation unit 22 Macro/expression Which gnulib module This compilation unit
@@ -34,12 +28,10 @@
34 || NEED_MKTIME_WINDOWS 28 || NEED_MKTIME_WINDOWS
35 29
36 NEED_MKTIME_INTERNAL mktime-internal mktime_internal 30 NEED_MKTIME_INTERNAL mktime-internal mktime_internal
37
38 DEBUG_MKTIME (defined manually) my_mktime, main
39 */ 31 */
40 32
41#if !defined _LIBC && !DEBUG_MKTIME 33#ifndef _LIBC
42# include <config.h> 34# include <libc-config.h>
43#endif 35#endif
44 36
45/* Assume that leap seconds are possible, unless told otherwise. 37/* Assume that leap seconds are possible, unless told otherwise.
@@ -51,6 +43,7 @@
51 43
52#include <time.h> 44#include <time.h>
53 45
46#include <errno.h>
54#include <limits.h> 47#include <limits.h>
55#include <stdbool.h> 48#include <stdbool.h>
56#include <stdlib.h> 49#include <stdlib.h>
@@ -59,13 +52,6 @@
59#include <intprops.h> 52#include <intprops.h>
60#include <verify.h> 53#include <verify.h>
61 54
62#if DEBUG_MKTIME
63# include <stdio.h>
64/* Make it work even if the system's libc has its own mktime routine. */
65# undef mktime
66# define mktime my_mktime
67#endif /* DEBUG_MKTIME */
68
69#ifndef NEED_MKTIME_INTERNAL 55#ifndef NEED_MKTIME_INTERNAL
70# define NEED_MKTIME_INTERNAL 0 56# define NEED_MKTIME_INTERNAL 0
71#endif 57#endif
@@ -73,7 +59,7 @@
73# define NEED_MKTIME_WINDOWS 0 59# define NEED_MKTIME_WINDOWS 0
74#endif 60#endif
75#ifndef NEED_MKTIME_WORKING 61#ifndef NEED_MKTIME_WORKING
76# define NEED_MKTIME_WORKING DEBUG_MKTIME 62# define NEED_MKTIME_WORKING 0
77#endif 63#endif
78 64
79#include "mktime-internal.h" 65#include "mktime-internal.h"
@@ -119,11 +105,12 @@ my_tzset (void)
119#if defined _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL 105#if defined _LIBC || NEED_MKTIME_WORKING || NEED_MKTIME_INTERNAL
120 106
121/* A signed type that can represent an integer number of years 107/* A signed type that can represent an integer number of years
122 multiplied by three times the number of seconds in a year. It is 108 multiplied by four times the number of seconds in a year. It is
123 needed when converting a tm_year value times the number of seconds 109 needed when converting a tm_year value times the number of seconds
124 in a year. The factor of three comes because these products need 110 in a year. The factor of four comes because these products need
125 to be subtracted from each other, and sometimes with an offset 111 to be subtracted from each other, and sometimes with an offset
126 added to them, without worrying about overflow. 112 added to them, and then with another timestamp added, without
113 worrying about overflow.
127 114
128 Much of the code uses long_int to represent time_t values, to 115 Much of the code uses long_int to represent time_t values, to
129 lessen the hassle of dealing with platforms where time_t is 116 lessen the hassle of dealing with platforms where time_t is
@@ -131,12 +118,12 @@ my_tzset (void)
131 time_t values that mktime can generate even on platforms where 118 time_t values that mktime can generate even on platforms where
132 time_t is excessively wide. */ 119 time_t is excessively wide. */
133 120
134#if INT_MAX <= LONG_MAX / 3 / 366 / 24 / 60 / 60 121#if INT_MAX <= LONG_MAX / 4 / 366 / 24 / 60 / 60
135typedef long int long_int; 122typedef long int long_int;
136#else 123#else
137typedef long long int long_int; 124typedef long long int long_int;
138#endif 125#endif
139verify (INT_MAX <= TYPE_MAXIMUM (long_int) / 3 / 366 / 24 / 60 / 60); 126verify (INT_MAX <= TYPE_MAXIMUM (long_int) / 4 / 366 / 24 / 60 / 60);
140 127
141/* Shift A right by B bits portably, by dividing A by 2**B and 128/* Shift A right by B bits portably, by dividing A by 2**B and
142 truncating towards minus infinity. B should be in the range 0 <= B 129 truncating towards minus infinity. B should be in the range 0 <= B
@@ -210,9 +197,10 @@ isdst_differ (int a, int b)
210 were not adjusted between the timestamps. 197 were not adjusted between the timestamps.
211 198
212 The YEAR values uses the same numbering as TP->tm_year. Values 199 The YEAR values uses the same numbering as TP->tm_year. Values
213 need not be in the usual range. However, YEAR1 must not overflow 200 need not be in the usual range. However, YEAR1 - YEAR0 must not
214 when multiplied by three times the number of seconds in a year, and 201 overflow even when multiplied by three times the number of seconds
215 likewise for YDAY1 and three times the number of seconds in a day. */ 202 in a year, and likewise for YDAY1 - YDAY0 and three times the
203 number of seconds in a day. */
216 204
217static long_int 205static long_int
218ydhms_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1, 206ydhms_diff (long_int year1, long_int yday1, int hour1, int min1, int sec1,
@@ -247,43 +235,25 @@ long_int_avg (long_int a, long_int b)
247 return shr (a, 1) + shr (b, 1) + ((a | b) & 1); 235 return shr (a, 1) + shr (b, 1) + ((a | b) & 1);
248} 236}
249 237
250/* Return a time_t value corresponding to (YEAR-YDAY HOUR:MIN:SEC), 238/* Return a long_int value corresponding to (YEAR-YDAY HOUR:MIN:SEC)
251 assuming that T corresponds to *TP and that no clock adjustments 239 minus *TP seconds, assuming no clock adjustments occurred between
252 occurred between *TP and the desired time. 240 the two timestamps.
253 Although T and the returned value are of type long_int, 241
254 they represent time_t values and must be in time_t range.
255 If TP is null, return a value not equal to T; this avoids false matches.
256 YEAR and YDAY must not be so large that multiplying them by three times the 242 YEAR and YDAY must not be so large that multiplying them by three times the
257 number of seconds in a year (or day, respectively) would overflow long_int. 243 number of seconds in a year (or day, respectively) would overflow long_int.
258 If the returned value would be out of range, yield the minimal or 244 *TP should be in the usual range. */
259 maximal in-range value, except do not yield a value equal to T. */
260static long_int 245static long_int
261guess_time_tm (long_int year, long_int yday, int hour, int min, int sec, 246tm_diff (long_int year, long_int yday, int hour, int min, int sec,
262 long_int t, const struct tm *tp) 247 struct tm const *tp)
263{ 248{
264 if (tp) 249 return ydhms_diff (year, yday, hour, min, sec,
265 { 250 tp->tm_year, tp->tm_yday,
266 long_int result; 251 tp->tm_hour, tp->tm_min, tp->tm_sec);
267 long_int d = ydhms_diff (year, yday, hour, min, sec,
268 tp->tm_year, tp->tm_yday,
269 tp->tm_hour, tp->tm_min, tp->tm_sec);
270 if (! INT_ADD_WRAPV (t, d, &result))
271 return result;
272 }
273
274 /* Overflow occurred one way or another. Return the nearest result
275 that is actually in range, except don't report a zero difference
276 if the actual difference is nonzero, as that would cause a false
277 match; and don't oscillate between two values, as that would
278 confuse the spring-forward gap detector. */
279 return (t < long_int_avg (mktime_min, mktime_max)
280 ? (t <= mktime_min + 1 ? t + 1 : mktime_min)
281 : (mktime_max - 1 <= t ? t - 1 : mktime_max));
282} 252}
283 253
284/* Use CONVERT to convert T to a struct tm value in *TM. T must be in 254/* Use CONVERT to convert T to a struct tm value in *TM. T must be in
285 range for time_t. Return TM if successful, NULL if T is out of 255 range for time_t. Return TM if successful, NULL (setting errno) on
286 range for CONVERT. */ 256 failure. */
287static struct tm * 257static struct tm *
288convert_time (struct tm *(*convert) (const time_t *, struct tm *), 258convert_time (struct tm *(*convert) (const time_t *, struct tm *),
289 long_int t, struct tm *tm) 259 long_int t, struct tm *tm)
@@ -295,47 +265,48 @@ convert_time (struct tm *(*convert) (const time_t *, struct tm *),
295/* Use CONVERT to convert *T to a broken down time in *TP. 265/* Use CONVERT to convert *T to a broken down time in *TP.
296 If *T is out of range for conversion, adjust it so that 266 If *T is out of range for conversion, adjust it so that
297 it is the nearest in-range value and then convert that. 267 it is the nearest in-range value and then convert that.
298 A value is in range if it fits in both time_t and long_int. */ 268 A value is in range if it fits in both time_t and long_int.
269 Return TP on success, NULL (setting errno) on failure. */
299static struct tm * 270static struct tm *
300ranged_convert (struct tm *(*convert) (const time_t *, struct tm *), 271ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
301 long_int *t, struct tm *tp) 272 long_int *t, struct tm *tp)
302{ 273{
303 struct tm *r; 274 long_int t1 = (*t < mktime_min ? mktime_min
304 if (*t < mktime_min) 275 : *t <= mktime_max ? *t : mktime_max);
305 *t = mktime_min; 276 struct tm *r = convert_time (convert, t1, tp);
306 else if (mktime_max < *t) 277 if (r)
307 *t = mktime_max;
308 r = convert_time (convert, *t, tp);
309
310 if (!r && *t)
311 { 278 {
312 long_int bad = *t; 279 *t = t1;
313 long_int ok = 0; 280 return r;
281 }
282 if (errno != EOVERFLOW)
283 return NULL;
314 284
315 /* BAD is a known unconvertible value, and OK is a known good one. 285 long_int bad = t1;
316 Use binary search to narrow the range between BAD and OK until 286 long_int ok = 0;
317 they differ by 1. */ 287 struct tm oktm; oktm.tm_sec = -1;
318 while (true)
319 {
320 long_int mid = long_int_avg (ok, bad);
321 if (mid != ok && mid != bad)
322 break;
323 r = convert_time (convert, mid, tp);
324 if (r)
325 ok = mid;
326 else
327 bad = mid;
328 }
329 288
330 if (!r && ok) 289 /* BAD is a known out-of-range value, and OK is a known in-range one.
331 { 290 Use binary search to narrow the range between BAD and OK until
332 /* The last conversion attempt failed; 291 they differ by 1. */
333 revert to the most recent successful attempt. */ 292 while (true)
334 r = convert_time (convert, ok, tp); 293 {
335 } 294 long_int mid = long_int_avg (ok, bad);
295 if (mid == ok || mid == bad)
296 break;
297 if (convert_time (convert, mid, tp))
298 ok = mid, oktm = *tp;
299 else if (errno != EOVERFLOW)
300 return NULL;
301 else
302 bad = mid;
336 } 303 }
337 304
338 return r; 305 if (oktm.tm_sec < 0)
306 return NULL;
307 *t = ok;
308 *tp = oktm;
309 return tp;
339} 310}
340 311
341 312
@@ -344,13 +315,14 @@ ranged_convert (struct tm *(*convert) (const time_t *, struct tm *),
344 Use *OFFSET to keep track of a guess at the offset of the result, 315 Use *OFFSET to keep track of a guess at the offset of the result,
345 compared to what the result would be for UTC without leap seconds. 316 compared to what the result would be for UTC without leap seconds.
346 If *OFFSET's guess is correct, only one CONVERT call is needed. 317 If *OFFSET's guess is correct, only one CONVERT call is needed.
318 If successful, set *TP to the canonicalized struct tm;
319 otherwise leave *TP alone, return ((time_t) -1) and set errno.
347 This function is external because it is used also by timegm.c. */ 320 This function is external because it is used also by timegm.c. */
348time_t 321time_t
349__mktime_internal (struct tm *tp, 322__mktime_internal (struct tm *tp,
350 struct tm *(*convert) (const time_t *, struct tm *), 323 struct tm *(*convert) (const time_t *, struct tm *),
351 mktime_offset_t *offset) 324 mktime_offset_t *offset)
352{ 325{
353 long_int t, gt, t0, t1, t2, dt;
354 struct tm tm; 326 struct tm tm;
355 327
356 /* The maximum number of probes (calls to CONVERT) should be enough 328 /* The maximum number of probes (calls to CONVERT) should be enough
@@ -370,7 +342,7 @@ __mktime_internal (struct tm *tp,
370 int isdst = tp->tm_isdst; 342 int isdst = tp->tm_isdst;
371 343
372 /* 1 if the previous probe was DST. */ 344 /* 1 if the previous probe was DST. */
373 int dst2; 345 int dst2 = 0;
374 346
375 /* Ensure that mon is in range, and set year accordingly. */ 347 /* Ensure that mon is in range, and set year accordingly. */
376 int mon_remainder = mon % 12; 348 int mon_remainder = mon % 12;
@@ -398,7 +370,7 @@ __mktime_internal (struct tm *tp,
398 if (LEAP_SECONDS_POSSIBLE) 370 if (LEAP_SECONDS_POSSIBLE)
399 { 371 {
400 /* Handle out-of-range seconds specially, 372 /* Handle out-of-range seconds specially,
401 since ydhms_tm_diff assumes every minute has 60 seconds. */ 373 since ydhms_diff assumes every minute has 60 seconds. */
402 if (sec < 0) 374 if (sec < 0)
403 sec = 0; 375 sec = 0;
404 if (59 < sec) 376 if (59 < sec)
@@ -409,33 +381,46 @@ __mktime_internal (struct tm *tp,
409 time. */ 381 time. */
410 382
411 INT_SUBTRACT_WRAPV (0, off, &negative_offset_guess); 383 INT_SUBTRACT_WRAPV (0, off, &negative_offset_guess);
412 t0 = ydhms_diff (year, yday, hour, min, sec, 384 long_int t0 = ydhms_diff (year, yday, hour, min, sec,
413 EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0, negative_offset_guess); 385 EPOCH_YEAR - TM_YEAR_BASE, 0, 0, 0,
386 negative_offset_guess);
387 long_int t = t0, t1 = t0, t2 = t0;
414 388
415 /* Repeatedly use the error to improve the guess. */ 389 /* Repeatedly use the error to improve the guess. */
416 390
417 for (t = t1 = t2 = t0, dst2 = 0; 391 while (true)
418 (gt = guess_time_tm (year, yday, hour, min, sec, t, 392 {
419 ranged_convert (convert, &t, &tm)), 393 if (! ranged_convert (convert, &t, &tm))
420 t != gt); 394 return -1;
421 t1 = t2, t2 = t, t = gt, dst2 = tm.tm_isdst != 0) 395 long_int dt = tm_diff (year, yday, hour, min, sec, &tm);
422 if (t == t1 && t != t2 396 if (dt == 0)
423 && (tm.tm_isdst < 0 397 break;
424 || (isdst < 0 398
425 ? dst2 <= (tm.tm_isdst != 0) 399 if (t == t1 && t != t2
426 : (isdst != 0) != (tm.tm_isdst != 0)))) 400 && (tm.tm_isdst < 0
427 /* We can't possibly find a match, as we are oscillating 401 || (isdst < 0
428 between two values. The requested time probably falls 402 ? dst2 <= (tm.tm_isdst != 0)
429 within a spring-forward gap of size GT - T. Follow the common 403 : (isdst != 0) != (tm.tm_isdst != 0))))
430 practice in this case, which is to return a time that is GT - T 404 /* We can't possibly find a match, as we are oscillating
431 away from the requested time, preferring a time whose 405 between two values. The requested time probably falls
432 tm_isdst differs from the requested value. (If no tm_isdst 406 within a spring-forward gap of size DT. Follow the common
433 was requested and only one of the two values has a nonzero 407 practice in this case, which is to return a time that is DT
434 tm_isdst, prefer that value.) In practice, this is more 408 away from the requested time, preferring a time whose
435 useful than returning -1. */ 409 tm_isdst differs from the requested value. (If no tm_isdst
436 goto offset_found; 410 was requested and only one of the two values has a nonzero
437 else if (--remaining_probes == 0) 411 tm_isdst, prefer that value.) In practice, this is more
438 return -1; 412 useful than returning -1. */
413 goto offset_found;
414
415 remaining_probes--;
416 if (remaining_probes == 0)
417 {
418 __set_errno (EOVERFLOW);
419 return -1;
420 }
421
422 t1 = t2, t2 = t, t += dt, dst2 = tm.tm_isdst != 0;
423 }
439 424
440 /* We have a match. Check whether tm.tm_isdst has the requested 425 /* We have a match. Check whether tm.tm_isdst has the requested
441 value, if any. */ 426 value, if any. */
@@ -477,25 +462,38 @@ __mktime_internal (struct tm *tp,
477 if (! INT_ADD_WRAPV (t, delta * direction, &ot)) 462 if (! INT_ADD_WRAPV (t, delta * direction, &ot))
478 { 463 {
479 struct tm otm; 464 struct tm otm;
480 ranged_convert (convert, &ot, &otm); 465 if (! ranged_convert (convert, &ot, &otm))
466 return -1;
481 if (! isdst_differ (isdst, otm.tm_isdst)) 467 if (! isdst_differ (isdst, otm.tm_isdst))
482 { 468 {
483 /* We found the desired tm_isdst. 469 /* We found the desired tm_isdst.
484 Extrapolate back to the desired time. */ 470 Extrapolate back to the desired time. */
485 t = guess_time_tm (year, yday, hour, min, sec, ot, &otm); 471 long_int gt = ot + tm_diff (year, yday, hour, min, sec,
486 ranged_convert (convert, &t, &tm); 472 &otm);
487 goto offset_found; 473 if (mktime_min <= gt && gt <= mktime_max)
474 {
475 if (convert_time (convert, gt, &tm))
476 {
477 t = gt;
478 goto offset_found;
479 }
480 if (errno != EOVERFLOW)
481 return -1;
482 }
488 } 483 }
489 } 484 }
490 } 485 }
486
487 __set_errno (EOVERFLOW);
488 return -1;
491 } 489 }
492 490
493 offset_found: 491 offset_found:
494 /* Set *OFFSET to the low-order bits of T - T0 - NEGATIVE_OFFSET_GUESS. 492 /* Set *OFFSET to the low-order bits of T - T0 - NEGATIVE_OFFSET_GUESS.
495 This is just a heuristic to speed up the next mktime call, and 493 This is just a heuristic to speed up the next mktime call, and
496 correctness is unaffected if integer overflow occurs here. */ 494 correctness is unaffected if integer overflow occurs here. */
497 INT_SUBTRACT_WRAPV (t, t0, &dt); 495 INT_SUBTRACT_WRAPV (t, t0, offset);
498 INT_SUBTRACT_WRAPV (dt, negative_offset_guess, offset); 496 INT_SUBTRACT_WRAPV (*offset, negative_offset_guess, offset);
499 497
500 if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec) 498 if (LEAP_SECONDS_POSSIBLE && sec_requested != tm.tm_sec)
501 { 499 {
@@ -505,8 +503,12 @@ __mktime_internal (struct tm *tp,
505 sec_adjustment -= sec; 503 sec_adjustment -= sec;
506 sec_adjustment += sec_requested; 504 sec_adjustment += sec_requested;
507 if (INT_ADD_WRAPV (t, sec_adjustment, &t) 505 if (INT_ADD_WRAPV (t, sec_adjustment, &t)
508 || ! (mktime_min <= t && t <= mktime_max) 506 || ! (mktime_min <= t && t <= mktime_max))
509 || ! convert_time (convert, t, &tm)) 507 {
508 __set_errno (EOVERFLOW);
509 return -1;
510 }
511 if (! convert_time (convert, t, &tm))
510 return -1; 512 return -1;
511 } 513 }
512 514
@@ -545,146 +547,3 @@ weak_alias (mktime, timelocal)
545libc_hidden_def (mktime) 547libc_hidden_def (mktime)
546libc_hidden_weak (timelocal) 548libc_hidden_weak (timelocal)
547#endif 549#endif
548
549#if DEBUG_MKTIME
550
551static int
552not_equal_tm (const struct tm *a, const struct tm *b)
553{
554 return ((a->tm_sec ^ b->tm_sec)
555 | (a->tm_min ^ b->tm_min)
556 | (a->tm_hour ^ b->tm_hour)
557 | (a->tm_mday ^ b->tm_mday)
558 | (a->tm_mon ^ b->tm_mon)
559 | (a->tm_year ^ b->tm_year)
560 | (a->tm_yday ^ b->tm_yday)
561 | isdst_differ (a->tm_isdst, b->tm_isdst));
562}
563
564static void
565print_tm (const struct tm *tp)
566{
567 if (tp)
568 printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
569 tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
570 tp->tm_hour, tp->tm_min, tp->tm_sec,
571 tp->tm_yday, tp->tm_wday, tp->tm_isdst);
572 else
573 printf ("0");
574}
575
576static int
577check_result (time_t tk, struct tm tmk, time_t tl, const struct tm *lt)
578{
579 if (tk != tl || !lt || not_equal_tm (&tmk, lt))
580 {
581 printf ("mktime (");
582 print_tm (lt);
583 printf (")\nyields (");
584 print_tm (&tmk);
585 printf (") == %ld, should be %ld\n", (long int) tk, (long int) tl);
586 return 1;
587 }
588
589 return 0;
590}
591
592int
593main (int argc, char **argv)
594{
595 int status = 0;
596 struct tm tm, tmk, tml;
597 struct tm *lt;
598 time_t tk, tl, tl1;
599 char trailer;
600
601 /* Sanity check, plus call tzset. */
602 tl = 0;
603 if (! localtime (&tl))
604 {
605 printf ("localtime (0) fails\n");
606 status = 1;
607 }
608
609 if ((argc == 3 || argc == 4)
610 && (sscanf (argv[1], "%d-%d-%d%c",
611 &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
612 == 3)
613 && (sscanf (argv[2], "%d:%d:%d%c",
614 &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
615 == 3))
616 {
617 tm.tm_year -= TM_YEAR_BASE;
618 tm.tm_mon--;
619 tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
620 tmk = tm;
621 tl = mktime (&tmk);
622 lt = localtime_r (&tl, &tml);
623 printf ("mktime returns %ld == ", (long int) tl);
624 print_tm (&tmk);
625 printf ("\n");
626 status = check_result (tl, tmk, tl, lt);
627 }
628 else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
629 {
630 time_t from = atol (argv[1]);
631 time_t by = atol (argv[2]);
632 time_t to = atol (argv[3]);
633
634 if (argc == 4)
635 for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
636 {
637 lt = localtime_r (&tl, &tml);
638 if (lt)
639 {
640 tmk = tml;
641 tk = mktime (&tmk);
642 status |= check_result (tk, tmk, tl, &tml);
643 }
644 else
645 {
646 printf ("localtime_r (%ld) yields 0\n", (long int) tl);
647 status = 1;
648 }
649 tl1 = tl + by;
650 if ((tl1 < tl) != (by < 0))
651 break;
652 }
653 else
654 for (tl = from; by < 0 ? to <= tl : tl <= to; tl = tl1)
655 {
656 /* Null benchmark. */
657 lt = localtime_r (&tl, &tml);
658 if (lt)
659 {
660 tmk = tml;
661 tk = tl;
662 status |= check_result (tk, tmk, tl, &tml);
663 }
664 else
665 {
666 printf ("localtime_r (%ld) yields 0\n", (long int) tl);
667 status = 1;
668 }
669 tl1 = tl + by;
670 if ((tl1 < tl) != (by < 0))
671 break;
672 }
673 }
674 else
675 printf ("Usage:\
676\t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
677\t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
678\t%s FROM BY TO - # Do not test those values (for benchmark).\n",
679 argv[0], argv[0], argv[0]);
680
681 return status;
682}
683
684#endif /* DEBUG_MKTIME */
685
686/*
687Local Variables:
688compile-command: "gcc -DDEBUG_MKTIME -I. -Wall -W -O2 -g mktime.c -o mktime"
689End:
690*/