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
5 __FBSDID("$FreeBSD: src/lib/libc/stdtime/strptime.c,v 1.35 2003/11/17 04:19:15 nectar Exp $");
7 +#include "xlocale_private.h"
19 #include "un-namespace.h"
20 #include "libc_private.h"
21 #include "timelocal.h"
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 *);
27 #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
29 +enum {CONVERT_NONE, CONVERT_GMT, CONVERT_ZONE};
31 +#define _strptime(b,f,t,c,l) _strptime0(b,f,t,c,l,-1,0,-1)
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)
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);
51 + while (isspace_l((unsigned char)*ptr, loc)) {
54 + return ((*ptr)==0) ? fmt : 0; /* trailing whitespace is ok */
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))
67 @@ -114,18 +129,18 @@ label:
71 - buf = _strptime(buf, tptr->date_fmt, tm, GMTp);
72 + buf = _strptime(buf, tptr->date_fmt, tm, convp, loc);
78 - if (!isdigit((unsigned char)*buf))
79 + if (!isdigit_l((unsigned char)*buf, loc))
82 /* XXX This will break for 3-digit centuries. */
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++) {
89 @@ -133,17 +148,21 @@ label:
94 + tm->tm_year = (year % 100) + i * 100 - 1900;
96 tm->tm_year = i * 100 - 1900;
101 - buf = _strptime(buf, tptr->c_fmt, tm, GMTp);
102 + buf = _strptime(buf, tptr->c_fmt, tm, convp, loc);
108 - buf = _strptime(buf, "%m/%d/%y", tm, GMTp);
109 + buf = _strptime(buf, "%m/%d/%y", tm, convp, loc);
113 @@ -161,47 +180,55 @@ label:
117 - buf = _strptime(buf, "%Y-%m-%d", tm, GMTp);
118 + buf = _strptime(buf, "%Y-%m-%d", tm, convp, loc);
124 - buf = _strptime(buf, "%H:%M", tm, GMTp);
125 + buf = _strptime(buf, "%H:%M", tm, convp, loc);
131 - buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp);
132 + buf = _strptime(buf, tptr->ampm_fmt, tm, convp, loc);
139 + if (!isspace((unsigned char)*buf))
141 + while (isspace((unsigned char)*buf))
146 - buf = _strptime(buf, "%H:%M:%S", tm, GMTp);
147 + buf = _strptime(buf, "%H:%M:%S", tm, convp, loc);
153 - buf = _strptime(buf, tptr->X_fmt, tm, GMTp);
154 + buf = _strptime(buf, tptr->X_fmt, tm, convp, loc);
160 - buf = _strptime(buf, tptr->x_fmt, tm, GMTp);
161 + buf = _strptime(buf, tptr->x_fmt, tm, convp, loc);
167 - if (!isdigit((unsigned char)*buf))
168 + if (!isdigit_l((unsigned char)*buf, loc))
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++) {
177 @@ -209,19 +236,19 @@ label:
178 if (i < 1 || i > 366)
181 - tm->tm_yday = i - 1;
182 + tm->tm_yday = yday = i - 1;
187 - if (*buf == 0 || isspace((unsigned char)*buf))
188 + if (*buf == 0 || isspace_l((unsigned char)*buf, loc))
191 - if (!isdigit((unsigned char)*buf))
192 + if (!isdigit_l((unsigned char)*buf, loc))
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++) {
201 @@ -237,8 +264,8 @@ label:
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 != '%')
212 @@ -254,11 +281,11 @@ label:
213 * XXX The %l specifier may gobble one too many
214 * digits if used incorrectly.
216 - if (!isdigit((unsigned char)*buf))
217 + if (!isdigit_l((unsigned char)*buf, loc))
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++) {
226 @@ -271,8 +298,8 @@ label:
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 != '%')
237 @@ -282,7 +309,7 @@ label:
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)
245 if (tm->tm_hour == 12)
246 @@ -292,7 +319,7 @@ label:
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)
254 if (tm->tm_hour != 12)
255 @@ -307,34 +334,28 @@ label:
257 for (i = 0; i < asizeof(tptr->weekday); i++) {
258 len = strlen(tptr->weekday[i]);
259 - if (strncasecmp(buf, tptr->weekday[i],
261 + if (strncasecmp_l(buf, tptr->weekday[i],
264 len = strlen(tptr->wday[i]);
265 - if (strncasecmp(buf, tptr->wday[i],
267 + if (strncasecmp_l(buf, tptr->wday[i],
271 if (i == asizeof(tptr->weekday))
275 + tm->tm_wday = wday = i;
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
287 - if (!isdigit((unsigned char)*buf))
288 + case 'U': /* Sunday week */
289 + case 'W': /* Monday week */
290 + if (!isdigit_l((unsigned char)*buf, loc))
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++) {
299 @@ -342,23 +363,46 @@ label:
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)) {
308 + mktm.tm_year = year;
312 + mktm.tm_min = mktm.tm_hour = 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;
323 + tm->tm_yday = yday;
326 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
327 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
332 - if (!isdigit((unsigned char)*buf))
333 + case 'u': /* [1,7] */
334 + case 'w': /* [0,6] */
335 + if (!isdigit_l((unsigned char)*buf, loc))
340 + if (i > 6 + (c == 'u'))
345 - if (*buf != 0 && isspace((unsigned char)*buf))
346 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
349 + tm->tm_wday = wday = i;
351 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
352 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
356 @@ -372,11 +416,18 @@ label:
357 * XXX The %e specifier may gobble one too many
358 * digits if used incorrectly.
360 - if (!isdigit((unsigned char)*buf))
361 + /* Leading space is ok if date is single digit */
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)) {
369 + if (!isdigit_l((unsigned char)*buf, loc))
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++) {
378 @@ -386,8 +437,8 @@ label:
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 != '%')
389 @@ -398,19 +449,19 @@ label:
392 len = strlen(tptr->alt_month[i]);
393 - if (strncasecmp(buf,
394 + if (strncasecmp_l(buf,
401 len = strlen(tptr->month[i]);
402 - if (strncasecmp(buf, tptr->month[i],
404 + if (strncasecmp_l(buf, tptr->month[i],
407 len = strlen(tptr->mon[i]);
408 - if (strncasecmp(buf, tptr->mon[i],
410 + if (strncasecmp_l(buf, tptr->mon[i],
415 @@ -422,11 +473,11 @@ label:
419 - if (!isdigit((unsigned char)*buf))
420 + if (!isdigit_l((unsigned char)*buf, loc))
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++) {
429 @@ -436,8 +487,8 @@ label:
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 != '%')
440 @@ -450,7 +501,7 @@ label:
444 - n = strtol(buf, &cp, 10);
445 + n = strtol_l(buf, &cp, 10, loc);
446 if (errno == ERANGE || (long)(t = n) != n) {
449 @@ -458,24 +509,82 @@ label:
454 + *convp = CONVERT_GMT;
460 - if (*buf == 0 || isspace((unsigned char)*buf))
461 + if (*buf == 0 || isspace_l((unsigned char)*buf, loc))
464 - if (!isdigit((unsigned char)*buf))
465 + if (!isdigit_l((unsigned char)*buf, loc))
471 + const char *savebuf = buf;
475 + for (len = 0; *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
482 + if (i64 > INT_MAX) {
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
496 + if (len > 4 && !overflow) {
497 + struct tm savetm = *tm;
498 + int saveconv = *convp;
499 + const char *saveptr = ptr;
505 + tm->tm_year = i64 - 1900;
507 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
508 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *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 */
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++) {
532 +#endif /* __DARWIN_UNIX03 */
535 if (c == 'y' && i < 69)
536 @@ -483,35 +592,58 @@ label:
541 + tm->tm_year = year = i;
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 != '%')
556 for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/}
558 - zonestr = alloca(cp - buf + 1);
559 - strncpy(zonestr, buf, cp - buf);
560 - zonestr[cp - buf] = '\0';
562 - if (0 == strcmp(zonestr, "GMT")) {
564 - } else if (0 == strcmp(zonestr, tzname[0])) {
566 - } else if (0 == strcmp(zonestr, tzname[1])) {
573 + if (len == 3 && strncmp(buf, "GMT", 3) == 0) {
574 + *convp = CONVERT_GMT;
579 + tzlen = strlen(tzname[0]);
580 + if (len == tzlen && strncmp(buf, tzname[0], tzlen) == 0) {
585 + tzlen = strlen(tzname[1]);
586 + if (len == tzlen && strncmp(buf, tzname[1], tzlen) == 0) {
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))
605 + sscanf(buf, "%c%2d%2d", &sign, &hr, &min);
606 + *convp = CONVERT_ZONE;
607 + tm->tm_gmtoff = 60 * (60 * hr + min);
609 + tm->tm_gmtoff = -tm->tm_gmtoff;
614 @@ -524,14 +656,39 @@ char *
615 strptime(const char * __restrict buf, const char * __restrict fmt,
616 struct tm * __restrict tm)
618 + return strptime_l(buf, fmt, tm, __current_locale());
621 +extern time_t timeoff(struct tm *, long);
624 +strptime_l(const char * __restrict buf, const char * __restrict fmt,
625 + struct tm * __restrict tm, locale_t loc)
632 - ret = _strptime(buf, fmt, tm, &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);
646 + localtime_r(&t, tm);
650 + long offset = tm->tm_gmtoff;
652 + t = timeoff(tm, offset);
653 + localtime_r(&t, tm);