aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mktime.c164
-rw-r--r--src/strftime.c6
2 files changed, 127 insertions, 43 deletions
diff --git a/src/mktime.c b/src/mktime.c
index a0cbce9a8f1..f759c29bb96 100644
--- a/src/mktime.c
+++ b/src/mktime.c
@@ -104,6 +104,9 @@ const unsigned short int __mon_yday[2][13] =
104 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } 104 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
105 }; 105 };
106 106
107static struct tm *ranged_convert __P ((struct tm *(*) __P ((const time_t *,
108 struct tm *)),
109 time_t *, struct tm *));
107static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *)); 110static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
108time_t __mktime_internal __P ((struct tm *, 111time_t __mktime_internal __P ((struct tm *,
109 struct tm *(*) (const time_t *, struct tm *), 112 struct tm *(*) (const time_t *, struct tm *),
@@ -136,30 +139,36 @@ localtime_r (t, tp)
136 measured in seconds, ignoring leap seconds. 139 measured in seconds, ignoring leap seconds.
137 YEAR uses the same numbering as TM->tm_year. 140 YEAR uses the same numbering as TM->tm_year.
138 All values are in range, except possibly YEAR. 141 All values are in range, except possibly YEAR.
142 If TP is null, return a nonzero value.
139 If overflow occurs, yield the low order bits of the correct answer. */ 143 If overflow occurs, yield the low order bits of the correct answer. */
140static time_t 144static time_t
141ydhms_tm_diff (year, yday, hour, min, sec, tp) 145ydhms_tm_diff (year, yday, hour, min, sec, tp)
142 int year, yday, hour, min, sec; 146 int year, yday, hour, min, sec;
143 const struct tm *tp; 147 const struct tm *tp;
144{ 148{
145 /* Compute intervening leap days correctly even if year is negative. 149 if (!tp)
146 Take care to avoid int overflow. time_t overflow is OK, since 150 return 1;
147 only the low order bits of the correct time_t answer are needed. 151 else
148 Don't convert to time_t until after all divisions are done, since 152 {
149 time_t might be unsigned. */ 153 /* Compute intervening leap days correctly even if year is negative.
150 int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3); 154 Take care to avoid int overflow. time_t overflow is OK, since
151 int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3); 155 only the low order bits of the correct time_t answer are needed.
152 int a100 = a4 / 25 - (a4 % 25 < 0); 156 Don't convert to time_t until after all divisions are done, since
153 int b100 = b4 / 25 - (b4 % 25 < 0); 157 time_t might be unsigned. */
154 int a400 = a100 >> 2; 158 int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
155 int b400 = b100 >> 2; 159 int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
156 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); 160 int a100 = a4 / 25 - (a4 % 25 < 0);
157 time_t years = year - (time_t) tp->tm_year; 161 int b100 = b4 / 25 - (b4 % 25 < 0);
158 time_t days = (365 * years + intervening_leap_days 162 int a400 = a100 >> 2;
159 + (yday - tp->tm_yday)); 163 int b400 = b100 >> 2;
160 return (60 * (60 * (24 * days + (hour - tp->tm_hour)) 164 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
161 + (min - tp->tm_min)) 165 time_t years = year - (time_t) tp->tm_year;
162 + (sec - tp->tm_sec)); 166 time_t days = (365 * years + intervening_leap_days
167 + (yday - tp->tm_yday));
168 return (60 * (60 * (24 * days + (hour - tp->tm_hour))
169 + (min - tp->tm_min))
170 + (sec - tp->tm_sec));
171 }
163} 172}
164 173
165 174
@@ -180,6 +189,54 @@ mktime (tp)
180 return __mktime_internal (tp, localtime_r, &localtime_offset); 189 return __mktime_internal (tp, localtime_r, &localtime_offset);
181} 190}
182 191
192/* Use CONVERT to convert *T to a broken down time in *TP.
193 If *T is out of range for conversion, adjust it so that
194 it is the nearest in-range value and then convert that. */
195static struct tm *
196ranged_convert (convert, t, tp)
197 struct tm *(*convert) __P ((const time_t *, struct tm *));
198 time_t *t;
199 struct tm *tp;
200{
201 struct tm *r;
202
203 if (! (r = (*convert) (t, tp)) && *t)
204 {
205 time_t bad = *t;
206 time_t ok = 0;
207 struct tm tm;
208
209 /* BAD is a known unconvertible time_t, and OK is a known good one.
210 Use binary search to narrow the range between BAD and OK until
211 they differ by 1. */
212 while (bad != ok + (bad < 0 ? -1 : 1))
213 {
214 time_t mid = *t = (bad < 0
215 ? bad + ((ok - bad) >> 1)
216 : ok + ((bad - ok) >> 1));
217 if ((r = (*convert) (t, tp)))
218 {
219 tm = *r;
220 ok = mid;
221 }
222 else
223 bad = mid;
224 }
225
226 if (!r && ok)
227 {
228 /* The last conversion attempt failed;
229 revert to the most recent successful attempt. */
230 *t = ok;
231 *tp = tm;
232 r = tp;
233 }
234 }
235
236 return r;
237}
238
239
183/* Convert *TP to a time_t value, inverting 240/* Convert *TP to a time_t value, inverting
184 the monotonic and mostly-unit-linear conversion function CONVERT. 241 the monotonic and mostly-unit-linear conversion function CONVERT.
185 Use *OFFSET to keep track of a guess at the offset of the result, 242 Use *OFFSET to keep track of a guess at the offset of the result,
@@ -245,7 +302,8 @@ __mktime_internal (tp, convert, offset)
245 t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm); 302 t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
246 303
247 for (t = t0 + *offset; 304 for (t = t0 + *offset;
248 (dt = ydhms_tm_diff (year, yday, hour, min, sec, (*convert) (&t, &tm))); 305 (dt = ydhms_tm_diff (year, yday, hour, min, sec,
306 ranged_convert (convert, &t, &tm)));
249 t += dt) 307 t += dt)
250 if (--remaining_probes == 0) 308 if (--remaining_probes == 0)
251 return -1; 309 return -1;
@@ -265,7 +323,7 @@ __mktime_internal (tp, convert, offset)
265 { 323 {
266 struct tm otm; 324 struct tm otm;
267 if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec, 325 if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
268 (*convert) (&ot, &otm)))) 326 ranged_convert (convert, &ot, &otm))))
269 { 327 {
270 t = ot; 328 t = ot;
271 tm = otm; 329 tm = otm;
@@ -285,7 +343,8 @@ __mktime_internal (tp, convert, offset)
285 /* Adjust time to reflect the tm_sec requested, not the normalized value. 343 /* Adjust time to reflect the tm_sec requested, not the normalized value.
286 Also, repair any damage from a false match due to a leap second. */ 344 Also, repair any damage from a false match due to a leap second. */
287 t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60); 345 t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
288 (*convert) (&t, &tm); 346 if (! (*convert) (&t, &tm))
347 return -1;
289 } 348 }
290#endif 349#endif
291 350
@@ -335,25 +394,28 @@ static void
335print_tm (tp) 394print_tm (tp)
336 struct tm *tp; 395 struct tm *tp;
337{ 396{
338 printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d", 397 if (tp)
339 tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday, 398 printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
340 tp->tm_hour, tp->tm_min, tp->tm_sec, 399 tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
341 tp->tm_yday, tp->tm_wday, tp->tm_isdst); 400 tp->tm_hour, tp->tm_min, tp->tm_sec,
401 tp->tm_yday, tp->tm_wday, tp->tm_isdst);
402 else
403 printf ("0");
342} 404}
343 405
344static int 406static int
345check_result (tk, tmk, tl, tml) 407check_result (tk, tmk, tl, lt)
346 time_t tk; 408 time_t tk;
347 struct tm tmk; 409 struct tm tmk;
348 time_t tl; 410 time_t tl;
349 struct tm tml; 411 struct tm *lt;
350{ 412{
351 if (tk != tl || not_equal_tm (&tmk, &tml)) 413 if (tk != tl || !lt || not_equal_tm (&tmk, lt))
352 { 414 {
353 printf ("mktime ("); 415 printf ("mktime (");
354 print_tm (&tmk); 416 print_tm (&tmk);
355 printf (")\nyields ("); 417 printf (")\nyields (");
356 print_tm (&tml); 418 print_tm (lt);
357 printf (") == %ld, should be %ld\n", (long) tl, (long) tk); 419 printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
358 return 1; 420 return 1;
359 } 421 }
@@ -368,6 +430,7 @@ main (argc, argv)
368{ 430{
369 int status = 0; 431 int status = 0;
370 struct tm tm, tmk, tml; 432 struct tm tm, tmk, tml;
433 struct tm *lt;
371 time_t tk, tl; 434 time_t tk, tl;
372 char trailer; 435 char trailer;
373 436
@@ -384,11 +447,16 @@ main (argc, argv)
384 tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]); 447 tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
385 tmk = tm; 448 tmk = tm;
386 tl = mktime (&tmk); 449 tl = mktime (&tmk);
387 tml = *localtime (&tl); 450 lt = localtime (&tl);
451 if (lt)
452 {
453 tml = *lt;
454 lt = &tml;
455 }
388 printf ("mktime returns %ld == ", (long) tl); 456 printf ("mktime returns %ld == ", (long) tl);
389 print_tm (&tmk); 457 print_tm (&tmk);
390 printf ("\n"); 458 printf ("\n");
391 status = check_result (tl, tmk, tl, tml); 459 status = check_result (tl, tmk, tl, lt);
392 } 460 }
393 else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0)) 461 else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
394 { 462 {
@@ -399,19 +467,35 @@ main (argc, argv)
399 if (argc == 4) 467 if (argc == 4)
400 for (tl = from; tl <= to; tl += by) 468 for (tl = from; tl <= to; tl += by)
401 { 469 {
402 tml = *localtime (&tl); 470 lt = localtime (&tl);
403 tmk = tml; 471 if (lt)
404 tk = mktime (&tmk); 472 {
405 status |= check_result (tk, tmk, tl, tml); 473 tmk = tml = *lt;
474 tk = mktime (&tmk);
475 status |= check_result (tk, tmk, tl, tml);
476 }
477 else
478 {
479 printf ("localtime (%ld) yields 0\n", (long) tl);
480 status = 1;
481 }
406 } 482 }
407 else 483 else
408 for (tl = from; tl <= to; tl += by) 484 for (tl = from; tl <= to; tl += by)
409 { 485 {
410 /* Null benchmark. */ 486 /* Null benchmark. */
411 tml = *localtime (&tl); 487 lt = localtime (&tl);
412 tmk = tml; 488 if (lt)
413 tk = tl; 489 {
414 status |= check_result (tk, tmk, tl, tml); 490 tmk = tml = *lt;
491 tk = tl;
492 status |= check_result (tk, tmk, tl, tml);
493 }
494 else
495 {
496 printf ("localtime (%ld) yields 0\n", (long) tl);
497 status = 1;
498 }
415 } 499 }
416 } 500 }
417 else 501 else
@@ -428,6 +512,6 @@ main (argc, argv)
428 512
429/* 513/*
430Local Variables: 514Local Variables:
431compile-command: "gcc -DDEBUG=1 -Wall -O -g mktime.c -o mktime" 515compile-command: "gcc -DDEBUG -D__EXTENSIONS__ -DHAVE_LIMITS_H -DHAVE_LOCALTIME_R -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime"
432End: 516End:
433*/ 517*/
diff --git a/src/strftime.c b/src/strftime.c
index 50aed8ac76a..b084851a451 100644
--- a/src/strftime.c
+++ b/src/strftime.c
@@ -184,7 +184,7 @@ localtime_r (t, tp)
184 return tp; 184 return tp;
185} 185}
186# endif /* ! HAVE_LOCALTIME_R */ 186# endif /* ! HAVE_LOCALTIME_R */
187#endif /* ! defined (_LIBC) */ 187#endif /* ! defined _LIBC */
188 188
189 189
190#if !defined memset && !defined HAVE_MEMSET && !defined _LIBC 190#if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
@@ -204,7 +204,7 @@ static const char zeroes[16] = /* "0000000000000000" */
204 do \ 204 do \
205 { \ 205 { \
206 int _this = _len > 16 ? 16 : _len; \ 206 int _this = _len > 16 ? 16 : _len; \
207 (P) = mempcpy ((P), spaces, _this); \ 207 (P) = MEMPCPY ((P), spaces, _this); \
208 _len -= _this; \ 208 _len -= _this; \
209 } \ 209 } \
210 while (_len > 0); \ 210 while (_len > 0); \
@@ -217,7 +217,7 @@ static const char zeroes[16] = /* "0000000000000000" */
217 do \ 217 do \
218 { \ 218 { \
219 int _this = _len > 16 ? 16 : _len; \ 219 int _this = _len > 16 ? 16 : _len; \
220 (P) = mempcpy ((P), zeroes, _this); \ 220 (P) = MEMPCPY ((P), zeroes, _this); \
221 _len -= _this; \ 221 _len -= _this; \
222 } \ 222 } \
223 while (_len > 0); \ 223 while (_len > 0); \