]> git.saurik.com Git - apple/libc.git/blob - stdtime/FreeBSD/strptime.c.patch
Libc-594.1.4.tar.gz
[apple/libc.git] / stdtime / FreeBSD / strptime.c.patch
1 --- strptime.c.orig 2009-03-04 16:49:20.000000000 -0800
2 +++ strptime.c 2009-05-13 16:39:36.000000000 -0700
3 @@ -61,41 +61,56 @@ static char sccsid[] __unused = "@(#)str
4 #endif /* not lint */
5 __FBSDID("$FreeBSD: src/lib/libc/stdtime/strptime.c,v 1.35 2003/11/17 04:19:15 nectar Exp $");
6
7 +#include "xlocale_private.h"
8 +
9 #include "namespace.h"
10 #include <time.h>
11 #include <ctype.h>
12 #include <errno.h>
13 +#include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <pthread.h>
17 +#include <stdint.h>
18 +#include <limits.h>
19 #include "un-namespace.h"
20 #include "libc_private.h"
21 #include "timelocal.h"
22
23 -static char * _strptime(const char *, const char *, struct tm *, int *);
24 +static char * _strptime(const char *, const char *, struct tm *, int *, locale_t) __DARWIN_ALIAS(_strptime);
25 +time_t _mktime(struct tm *, const char *);
26
27 #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
28
29 +enum {CONVERT_NONE, CONVERT_GMT, CONVERT_ZONE};
30 +
31 +#define _strptime(b,f,t,c,l) _strptime0(b,f,t,c,l,-1,0,-1)
32 +
33 static char *
34 -_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp)
35 +_strptime0(const char *buf, const char *fmt, struct tm *tm, int *convp, locale_t loc, int year, int yday, int wday)
36 {
37 char c;
38 const char *ptr;
39 int i,
40 len;
41 int Ealternative, Oalternative;
42 - struct lc_time_T *tptr = __get_current_time_locale();
43 + struct lc_time_T *tptr = __get_current_time_locale(loc);
44
45 ptr = fmt;
46 while (*ptr != 0) {
47 - if (*buf == 0)
48 - break;
49 + if (*buf == 0) {
50 + fmt = ptr;
51 + while (isspace_l((unsigned char)*ptr, loc)) {
52 + ptr++;
53 + }
54 + return ((*ptr)==0) ? fmt : 0; /* trailing whitespace is ok */
55 + }
56
57 c = *ptr++;
58
59 if (c != '%') {
60 - if (isspace((unsigned char)c))
61 - while (*buf != 0 && isspace((unsigned char)*buf))
62 + if (isspace_l((unsigned char)c, loc))
63 + while (*buf != 0 && isspace_l((unsigned char)*buf, loc))
64 buf++;
65 else if (c != *buf++)
66 return 0;
67 @@ -114,18 +129,18 @@ label:
68 break;
69
70 case '+':
71 - buf = _strptime(buf, tptr->date_fmt, tm, GMTp);
72 + buf = _strptime(buf, tptr->date_fmt, tm, convp, loc);
73 if (buf == 0)
74 return 0;
75 break;
76
77 case 'C':
78 - if (!isdigit((unsigned char)*buf))
79 + if (!isdigit_l((unsigned char)*buf, loc))
80 return 0;
81
82 /* XXX This will break for 3-digit centuries. */
83 len = 2;
84 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
85 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
86 i *= 10;
87 i += *buf - '0';
88 len--;
89 @@ -133,17 +148,21 @@ label:
90 if (i < 19)
91 return 0;
92
93 + if (year != -1)
94 + tm->tm_year = (year % 100) + i * 100 - 1900;
95 + else
96 tm->tm_year = i * 100 - 1900;
97 + year = tm->tm_year;
98 break;
99
100 case 'c':
101 - buf = _strptime(buf, tptr->c_fmt, tm, GMTp);
102 + buf = _strptime(buf, tptr->c_fmt, tm, convp, loc);
103 if (buf == 0)
104 return 0;
105 break;
106
107 case 'D':
108 - buf = _strptime(buf, "%m/%d/%y", tm, GMTp);
109 + buf = _strptime(buf, "%m/%d/%y", tm, convp, loc);
110 if (buf == 0)
111 return 0;
112 break;
113 @@ -161,47 +180,55 @@ label:
114 goto label;
115
116 case 'F':
117 - buf = _strptime(buf, "%Y-%m-%d", tm, GMTp);
118 + buf = _strptime(buf, "%Y-%m-%d", tm, convp, loc);
119 if (buf == 0)
120 return 0;
121 break;
122
123 case 'R':
124 - buf = _strptime(buf, "%H:%M", tm, GMTp);
125 + buf = _strptime(buf, "%H:%M", tm, convp, loc);
126 if (buf == 0)
127 return 0;
128 break;
129
130 case 'r':
131 - buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp);
132 + buf = _strptime(buf, tptr->ampm_fmt, tm, convp, loc);
133 if (buf == 0)
134 return 0;
135 break;
136
137 + case 'n':
138 + case 't':
139 + if (!isspace((unsigned char)*buf))
140 + return 0;
141 + while (isspace((unsigned char)*buf))
142 + buf++;
143 + break;
144 +
145 case 'T':
146 - buf = _strptime(buf, "%H:%M:%S", tm, GMTp);
147 + buf = _strptime(buf, "%H:%M:%S", tm, convp, loc);
148 if (buf == 0)
149 return 0;
150 break;
151
152 case 'X':
153 - buf = _strptime(buf, tptr->X_fmt, tm, GMTp);
154 + buf = _strptime(buf, tptr->X_fmt, tm, convp, loc);
155 if (buf == 0)
156 return 0;
157 break;
158
159 case 'x':
160 - buf = _strptime(buf, tptr->x_fmt, tm, GMTp);
161 + buf = _strptime(buf, tptr->x_fmt, tm, convp, loc);
162 if (buf == 0)
163 return 0;
164 break;
165
166 case 'j':
167 - if (!isdigit((unsigned char)*buf))
168 + if (!isdigit_l((unsigned char)*buf, loc))
169 return 0;
170
171 len = 3;
172 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
173 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
174 i *= 10;
175 i += *buf - '0';
176 len--;
177 @@ -209,19 +236,19 @@ label:
178 if (i < 1 || i > 366)
179 return 0;
180
181 - tm->tm_yday = i - 1;
182 + tm->tm_yday = yday = i - 1;
183 break;
184
185 case 'M':
186 case 'S':
187 - if (*buf == 0 || isspace((unsigned char)*buf))
188 + if (*buf == 0 || isspace_l((unsigned char)*buf, loc))
189 break;
190
191 - if (!isdigit((unsigned char)*buf))
192 + if (!isdigit_l((unsigned char)*buf, loc))
193 return 0;
194
195 len = 2;
196 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
197 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
198 i *= 10;
199 i += *buf - '0';
200 len--;
201 @@ -237,8 +264,8 @@ label:
202 tm->tm_sec = i;
203 }
204
205 - if (*buf != 0 && isspace((unsigned char)*buf))
206 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
207 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
208 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
209 ptr++;
210 break;
211
212 @@ -254,11 +281,11 @@ label:
213 * XXX The %l specifier may gobble one too many
214 * digits if used incorrectly.
215 */
216 - if (!isdigit((unsigned char)*buf))
217 + if (!isdigit_l((unsigned char)*buf, loc))
218 return 0;
219
220 len = 2;
221 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
222 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
223 i *= 10;
224 i += *buf - '0';
225 len--;
226 @@ -271,8 +298,8 @@ label:
227
228 tm->tm_hour = i;
229
230 - if (*buf != 0 && isspace((unsigned char)*buf))
231 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
232 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
233 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
234 ptr++;
235 break;
236
237 @@ -282,7 +309,7 @@ label:
238 * specifiers.
239 */
240 len = strlen(tptr->am);
241 - if (strncasecmp(buf, tptr->am, len) == 0) {
242 + if (strncasecmp_l(buf, tptr->am, len, loc) == 0) {
243 if (tm->tm_hour > 12)
244 return 0;
245 if (tm->tm_hour == 12)
246 @@ -292,7 +319,7 @@ label:
247 }
248
249 len = strlen(tptr->pm);
250 - if (strncasecmp(buf, tptr->pm, len) == 0) {
251 + if (strncasecmp_l(buf, tptr->pm, len, loc) == 0) {
252 if (tm->tm_hour > 12)
253 return 0;
254 if (tm->tm_hour != 12)
255 @@ -307,34 +334,28 @@ label:
256 case 'a':
257 for (i = 0; i < asizeof(tptr->weekday); i++) {
258 len = strlen(tptr->weekday[i]);
259 - if (strncasecmp(buf, tptr->weekday[i],
260 - len) == 0)
261 + if (strncasecmp_l(buf, tptr->weekday[i],
262 + len, loc) == 0)
263 break;
264 len = strlen(tptr->wday[i]);
265 - if (strncasecmp(buf, tptr->wday[i],
266 - len) == 0)
267 + if (strncasecmp_l(buf, tptr->wday[i],
268 + len, loc) == 0)
269 break;
270 }
271 if (i == asizeof(tptr->weekday))
272 return 0;
273
274 - tm->tm_wday = i;
275 + tm->tm_wday = wday = i;
276 buf += len;
277 break;
278
279 - case 'U':
280 - case 'W':
281 - /*
282 - * XXX This is bogus, as we can not assume any valid
283 - * information present in the tm structure at this
284 - * point to calculate a real value, so just check the
285 - * range for now.
286 - */
287 - if (!isdigit((unsigned char)*buf))
288 + case 'U': /* Sunday week */
289 + case 'W': /* Monday week */
290 + if (!isdigit_l((unsigned char)*buf, loc))
291 return 0;
292
293 len = 2;
294 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
295 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
296 i *= 10;
297 i += *buf - '0';
298 len--;
299 @@ -342,23 +363,46 @@ label:
300 if (i > 53)
301 return 0;
302
303 - if (*buf != 0 && isspace((unsigned char)*buf))
304 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
305 + /* Calculate yday if we have enough data */
306 + if ((year != -1) && (wday != -1)) {
307 + struct tm mktm;
308 + mktm.tm_year = year;
309 + mktm.tm_mon = 0;
310 + mktm.tm_mday = 1;
311 + mktm.tm_sec = 1;
312 + mktm.tm_min = mktm.tm_hour = 0;
313 + mktm.tm_isdst = 0;
314 + mktm.tm_gmtoff = 0;
315 + if (mktime(&mktm) != -1) {
316 + /* yday0 == Jan 1 == mktm.tm_wday */
317 + int delta = wday - mktm.tm_wday;
318 + if (!wday && c =='W')
319 + i++; /* Sunday is part of the following week */
320 + yday = 7 * i + delta;
321 + if (yday < 0)
322 + yday += 7;
323 + tm->tm_yday = yday;
324 + }
325 + }
326 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
327 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
328 ptr++;
329 break;
330
331 - case 'w':
332 - if (!isdigit((unsigned char)*buf))
333 + case 'u': /* [1,7] */
334 + case 'w': /* [0,6] */
335 + if (!isdigit_l((unsigned char)*buf, loc))
336 return 0;
337
338 i = *buf - '0';
339 - if (i > 6)
340 + if (i > 6 + (c == 'u'))
341 return 0;
342 -
343 - tm->tm_wday = i;
344 -
345 - if (*buf != 0 && isspace((unsigned char)*buf))
346 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
347 + if (i == 7)
348 + i = 0;
349 + tm->tm_wday = wday = i;
350 + buf++;
351 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
352 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
353 ptr++;
354 break;
355
356 @@ -372,11 +416,18 @@ label:
357 * XXX The %e specifier may gobble one too many
358 * digits if used incorrectly.
359 */
360 - if (!isdigit((unsigned char)*buf))
361 + /* Leading space is ok if date is single digit */
362 + len = 2;
363 + if (isspace_l((unsigned char)buf[0], loc) &&
364 + isdigit_l((unsigned char)buf[1], loc) &&
365 + !isdigit_l((unsigned char)buf[2], loc)) {
366 + len = 1;
367 + buf++;
368 + }
369 + if (!isdigit_l((unsigned char)*buf, loc))
370 return 0;
371
372 - len = 2;
373 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
374 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
375 i *= 10;
376 i += *buf - '0';
377 len--;
378 @@ -386,8 +437,8 @@ label:
379
380 tm->tm_mday = i;
381
382 - if (*buf != 0 && isspace((unsigned char)*buf))
383 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
384 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
385 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
386 ptr++;
387 break;
388
389 @@ -398,19 +449,19 @@ label:
390 if (Oalternative) {
391 if (c == 'B') {
392 len = strlen(tptr->alt_month[i]);
393 - if (strncasecmp(buf,
394 + if (strncasecmp_l(buf,
395 tptr->alt_month[i],
396 - len) == 0)
397 + len, loc) == 0)
398 break;
399 }
400 } else {
401 len = strlen(tptr->month[i]);
402 - if (strncasecmp(buf, tptr->month[i],
403 - len) == 0)
404 + if (strncasecmp_l(buf, tptr->month[i],
405 + len, loc) == 0)
406 break;
407 len = strlen(tptr->mon[i]);
408 - if (strncasecmp(buf, tptr->mon[i],
409 - len) == 0)
410 + if (strncasecmp_l(buf, tptr->mon[i],
411 + len, loc) == 0)
412 break;
413 }
414 }
415 @@ -422,11 +473,11 @@ label:
416 break;
417
418 case 'm':
419 - if (!isdigit((unsigned char)*buf))
420 + if (!isdigit_l((unsigned char)*buf, loc))
421 return 0;
422
423 len = 2;
424 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
425 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
426 i *= 10;
427 i += *buf - '0';
428 len--;
429 @@ -436,8 +487,8 @@ label:
430
431 tm->tm_mon = i - 1;
432
433 - if (*buf != 0 && isspace((unsigned char)*buf))
434 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
435 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
436 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
437 ptr++;
438 break;
439
440 @@ -450,7 +501,7 @@ label:
441
442 sverrno = errno;
443 errno = 0;
444 - n = strtol(buf, &cp, 10);
445 + n = strtol_l(buf, &cp, 10, loc);
446 if (errno == ERANGE || (long)(t = n) != n) {
447 errno = sverrno;
448 return 0;
449 @@ -458,24 +509,82 @@ label:
450 errno = sverrno;
451 buf = cp;
452 gmtime_r(&t, tm);
453 - *GMTp = 1;
454 + *convp = CONVERT_GMT;
455 }
456 break;
457
458 case 'Y':
459 case 'y':
460 - if (*buf == 0 || isspace((unsigned char)*buf))
461 + if (*buf == 0 || isspace_l((unsigned char)*buf, loc))
462 break;
463
464 - if (!isdigit((unsigned char)*buf))
465 + if (!isdigit_l((unsigned char)*buf, loc))
466 return 0;
467
468 +#if __DARWIN_UNIX03
469 + if (c == 'Y') {
470 + int savei = 0;
471 + const char *savebuf = buf;
472 + int64_t i64 = 0;
473 + int overflow = 0;
474 +
475 + for (len = 0; *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
476 + i64 *= 10;
477 + i64 += *buf - '0';
478 + if (++len <= 4) {
479 + savei = i64;
480 + savebuf = buf + 1;
481 + }
482 + if (i64 > INT_MAX) {
483 + overflow++;
484 + break;
485 + }
486 + }
487 + /*
488 + * Conformance requires %Y to be more then 4
489 + * digits. However, there are several cases
490 + * where %Y is immediately followed by other
491 + * digits values. So we do the conformance
492 + * case first (as many digits as possible),
493 + * and if we fail, we backup and try just 4
494 + * digits for %Y.
495 + */
496 + if (len > 4 && !overflow) {
497 + struct tm savetm = *tm;
498 + int saveconv = *convp;
499 + const char *saveptr = ptr;
500 + char *ret;
501 +
502 + if (i64 < 1900)
503 + return 0;
504 +
505 + tm->tm_year = i64 - 1900;
506 +
507 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
508 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
509 + ptr++;
510 + ret = _strptime0(buf, ptr, tm, convp, loc, tm->tm_year, yday, wday);
511 + if (ret) return ret;
512 + /* Failed, so try 4-digit year */
513 + *tm = savetm;
514 + *convp = saveconv;
515 + ptr = saveptr;
516 + }
517 + buf = savebuf;
518 + i = savei;
519 + } else {
520 + len = 2;
521 +#else /* !__DARWIN_UNIX03 */
522 len = (c == 'Y') ? 4 : 2;
523 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
524 +#endif /* __DARWIN_UNIX03 */
525 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
526 i *= 10;
527 i += *buf - '0';
528 len--;
529 }
530 +#if __DARWIN_UNIX03
531 + }
532 +#endif /* __DARWIN_UNIX03 */
533 if (c == 'Y')
534 i -= 1900;
535 if (c == 'y' && i < 69)
536 @@ -483,35 +592,58 @@ label:
537 if (i < 0)
538 return 0;
539
540 - tm->tm_year = i;
541 + tm->tm_year = year = i;
542
543 - if (*buf != 0 && isspace((unsigned char)*buf))
544 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
545 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
546 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
547 ptr++;
548 break;
549
550 case 'Z':
551 {
552 const char *cp;
553 - char *zonestr;
554 + size_t tzlen, len;
555
556 for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/}
557 - if (cp - buf) {
558 - zonestr = alloca(cp - buf + 1);
559 - strncpy(zonestr, buf, cp - buf);
560 - zonestr[cp - buf] = '\0';
561 - tzset();
562 - if (0 == strcmp(zonestr, "GMT")) {
563 - *GMTp = 1;
564 - } else if (0 == strcmp(zonestr, tzname[0])) {
565 - tm->tm_isdst = 0;
566 - } else if (0 == strcmp(zonestr, tzname[1])) {
567 - tm->tm_isdst = 1;
568 - } else {
569 - return 0;
570 - }
571 - buf += cp - buf;
572 + len = cp - buf;
573 + if (len == 3 && strncmp(buf, "GMT", 3) == 0) {
574 + *convp = CONVERT_GMT;
575 + buf += len;
576 + break;
577 + }
578 + tzset();
579 + tzlen = strlen(tzname[0]);
580 + if (len == tzlen && strncmp(buf, tzname[0], tzlen) == 0) {
581 + tm->tm_isdst = 0;
582 + buf += len;
583 + break;
584 + }
585 + tzlen = strlen(tzname[1]);
586 + if (len == tzlen && strncmp(buf, tzname[1], tzlen) == 0) {
587 + tm->tm_isdst = 1;
588 + buf += len;
589 + break;
590 }
591 + return 0;
592 + }
593 +
594 + case 'z':
595 + {
596 + char sign;
597 + int hr, min;
598 +
599 + if ((buf[0] != '+' && buf[0] != '-')
600 + || !isdigit_l((unsigned char)buf[1], loc)
601 + || !isdigit_l((unsigned char)buf[2], loc)
602 + || !isdigit_l((unsigned char)buf[3], loc)
603 + || !isdigit_l((unsigned char)buf[4], loc))
604 + return 0;
605 + sscanf(buf, "%c%2d%2d", &sign, &hr, &min);
606 + *convp = CONVERT_ZONE;
607 + tm->tm_gmtoff = 60 * (60 * hr + min);
608 + if (sign == '-')
609 + tm->tm_gmtoff = -tm->tm_gmtoff;
610 + buf += 5;
611 }
612 break;
613 }
614 @@ -524,14 +656,39 @@ char *
615 strptime(const char * __restrict buf, const char * __restrict fmt,
616 struct tm * __restrict tm)
617 {
618 + return strptime_l(buf, fmt, tm, __current_locale());
619 +}
620 +
621 +extern time_t timeoff(struct tm *, long);
622 +
623 +char *
624 +strptime_l(const char * __restrict buf, const char * __restrict fmt,
625 + struct tm * __restrict tm, locale_t loc)
626 +{
627 char *ret;
628 - int gmt;
629 + int conv;
630
631 - gmt = 0;
632 - ret = _strptime(buf, fmt, tm, &gmt);
633 - if (ret && gmt) {
634 - time_t t = timegm(tm);
635 - localtime_r(&t, tm);
636 + NORMALIZE_LOCALE(loc);
637 + conv = CONVERT_NONE;
638 + tm->tm_zone = NULL;
639 + ret = _strptime(buf, fmt, tm, &conv, loc);
640 + if (ret) {
641 + time_t t;
642 +
643 + switch(conv) {
644 + case CONVERT_GMT:
645 + t = timegm(tm);
646 + localtime_r(&t, tm);
647 + break;
648 + case CONVERT_ZONE:
649 + {
650 + long offset = tm->tm_gmtoff;
651 + tm->tm_gmtoff = 0;
652 + t = timeoff(tm, offset);
653 + localtime_r(&t, tm);
654 + break;
655 + }
656 + }
657 }
658
659 return (ret);