1 --- strptime.c.orig 2009-11-14 13:55:44.000000000 -0800
2 +++ strptime.c 2009-11-18 16:56:27.000000000 -0800
3 @@ -61,41 +61,55 @@ static char sccsid[] __unused = "@(#)str
5 __FBSDID("$FreeBSD: src/lib/libc/stdtime/strptime.c,v 1.37 2009/09/02 04:56:30 ache 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 +time_t _mktime(struct tm *, const char *);
26 #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
28 +enum {CONVERT_NONE, CONVERT_GMT, CONVERT_ZONE};
30 +#define _strptime(b,f,t,c,l) _strptime0(b,f,t,c,l,-1,0,-1)
33 -_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp)
34 +_strptime0(const char *buf, const char *fmt, struct tm *tm, int *convp, locale_t loc, int year, int yday, int wday)
40 int Ealternative, Oalternative;
41 - struct lc_time_T *tptr = __get_current_time_locale();
42 + struct lc_time_T *tptr = __get_current_time_locale(loc);
50 + while (isspace_l((unsigned char)*ptr, loc)) {
53 + return ((*ptr)==0) ? (char *)fmt : 0; /* trailing whitespace is ok */
59 - if (isspace((unsigned char)c))
60 - while (*buf != 0 && isspace((unsigned char)*buf))
61 + if (isspace_l((unsigned char)c, loc))
62 + while (*buf != 0 && isspace_l((unsigned char)*buf, loc))
66 @@ -114,18 +128,18 @@ label:
70 - buf = _strptime(buf, tptr->date_fmt, tm, GMTp);
71 + buf = _strptime(buf, tptr->date_fmt, tm, convp, loc);
77 - if (!isdigit((unsigned char)*buf))
78 + if (!isdigit_l((unsigned char)*buf, loc))
81 /* XXX This will break for 3-digit centuries. */
83 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
84 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
88 @@ -133,17 +147,21 @@ label:
93 + tm->tm_year = (year % 100) + i * 100 - 1900;
95 tm->tm_year = i * 100 - 1900;
100 - buf = _strptime(buf, tptr->c_fmt, tm, GMTp);
101 + buf = _strptime(buf, tptr->c_fmt, tm, convp, loc);
107 - buf = _strptime(buf, "%m/%d/%y", tm, GMTp);
108 + buf = _strptime(buf, "%m/%d/%y", tm, convp, loc);
112 @@ -161,47 +179,55 @@ label:
116 - buf = _strptime(buf, "%Y-%m-%d", tm, GMTp);
117 + buf = _strptime(buf, "%Y-%m-%d", tm, convp, loc);
123 - buf = _strptime(buf, "%H:%M", tm, GMTp);
124 + buf = _strptime(buf, "%H:%M", tm, convp, loc);
130 - buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp);
131 + buf = _strptime(buf, tptr->ampm_fmt, tm, convp, loc);
138 + if (!isspace((unsigned char)*buf))
140 + while (isspace((unsigned char)*buf))
145 - buf = _strptime(buf, "%H:%M:%S", tm, GMTp);
146 + buf = _strptime(buf, "%H:%M:%S", tm, convp, loc);
152 - buf = _strptime(buf, tptr->X_fmt, tm, GMTp);
153 + buf = _strptime(buf, tptr->X_fmt, tm, convp, loc);
159 - buf = _strptime(buf, tptr->x_fmt, tm, GMTp);
160 + buf = _strptime(buf, tptr->x_fmt, tm, convp, loc);
166 - if (!isdigit((unsigned char)*buf))
167 + if (!isdigit_l((unsigned char)*buf, loc))
171 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
172 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
176 @@ -209,19 +235,19 @@ label:
177 if (i < 1 || i > 366)
180 - tm->tm_yday = i - 1;
181 + tm->tm_yday = yday = i - 1;
186 - if (*buf == 0 || isspace((unsigned char)*buf))
187 + if (*buf == 0 || isspace_l((unsigned char)*buf, loc))
190 - if (!isdigit((unsigned char)*buf))
191 + if (!isdigit_l((unsigned char)*buf, loc))
195 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
196 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
200 @@ -237,8 +263,8 @@ label:
204 - if (*buf != 0 && isspace((unsigned char)*buf))
205 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
206 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
207 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
211 @@ -254,11 +280,11 @@ label:
212 * XXX The %l specifier may gobble one too many
213 * digits if used incorrectly.
215 - if (!isdigit((unsigned char)*buf))
216 + if (!isdigit_l((unsigned char)*buf, loc))
220 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
221 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
225 @@ -271,8 +297,8 @@ label:
229 - if (*buf != 0 && isspace((unsigned char)*buf))
230 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
231 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
232 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
236 @@ -282,7 +308,7 @@ label:
239 len = strlen(tptr->am);
240 - if (strncasecmp(buf, tptr->am, len) == 0) {
241 + if (strncasecmp_l(buf, tptr->am, len, loc) == 0) {
242 if (tm->tm_hour > 12)
244 if (tm->tm_hour == 12)
245 @@ -292,7 +318,7 @@ label:
248 len = strlen(tptr->pm);
249 - if (strncasecmp(buf, tptr->pm, len) == 0) {
250 + if (strncasecmp_l(buf, tptr->pm, len, loc) == 0) {
251 if (tm->tm_hour > 12)
253 if (tm->tm_hour != 12)
254 @@ -307,34 +333,28 @@ label:
256 for (i = 0; i < asizeof(tptr->weekday); i++) {
257 len = strlen(tptr->weekday[i]);
258 - if (strncasecmp(buf, tptr->weekday[i],
260 + if (strncasecmp_l(buf, tptr->weekday[i],
263 len = strlen(tptr->wday[i]);
264 - if (strncasecmp(buf, tptr->wday[i],
266 + if (strncasecmp_l(buf, tptr->wday[i],
270 if (i == asizeof(tptr->weekday))
274 + tm->tm_wday = wday = i;
281 - * XXX This is bogus, as we can not assume any valid
282 - * information present in the tm structure at this
283 - * point to calculate a real value, so just check the
286 - if (!isdigit((unsigned char)*buf))
287 + case 'U': /* Sunday week */
288 + case 'W': /* Monday week */
289 + if (!isdigit_l((unsigned char)*buf, loc))
293 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
294 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
298 @@ -342,23 +362,46 @@ label:
302 - if (*buf != 0 && isspace((unsigned char)*buf))
303 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
304 + /* Calculate yday if we have enough data */
305 + if ((year != -1) && (wday != -1)) {
307 + mktm.tm_year = year;
311 + mktm.tm_min = mktm.tm_hour = 0;
313 + mktm.tm_gmtoff = 0;
314 + if (mktime(&mktm) != -1) {
315 + /* yday0 == Jan 1 == mktm.tm_wday */
316 + int delta = wday - mktm.tm_wday;
317 + if (!wday && c =='W')
318 + i++; /* Sunday is part of the following week */
319 + yday = 7 * i + delta;
322 + tm->tm_yday = yday;
325 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
326 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
331 - if (!isdigit((unsigned char)*buf))
332 + case 'u': /* [1,7] */
333 + case 'w': /* [0,6] */
334 + if (!isdigit_l((unsigned char)*buf, loc))
339 + if (i > 6 + (c == 'u'))
344 - if (*buf != 0 && isspace((unsigned char)*buf))
345 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
348 + tm->tm_wday = wday = i;
350 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
351 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
355 @@ -372,11 +415,18 @@ label:
356 * XXX The %e specifier may gobble one too many
357 * digits if used incorrectly.
359 - if (!isdigit((unsigned char)*buf))
360 + /* Leading space is ok if date is single digit */
362 + if (isspace_l((unsigned char)buf[0], loc) &&
363 + isdigit_l((unsigned char)buf[1], loc) &&
364 + !isdigit_l((unsigned char)buf[2], loc)) {
368 + if (!isdigit_l((unsigned char)*buf, loc))
372 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
373 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
377 @@ -386,8 +436,8 @@ label:
381 - if (*buf != 0 && isspace((unsigned char)*buf))
382 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
383 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
384 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
388 @@ -398,19 +448,19 @@ label:
391 len = strlen(tptr->alt_month[i]);
392 - if (strncasecmp(buf,
393 + if (strncasecmp_l(buf,
400 len = strlen(tptr->month[i]);
401 - if (strncasecmp(buf, tptr->month[i],
403 + if (strncasecmp_l(buf, tptr->month[i],
406 len = strlen(tptr->mon[i]);
407 - if (strncasecmp(buf, tptr->mon[i],
409 + if (strncasecmp_l(buf, tptr->mon[i],
414 @@ -422,11 +472,11 @@ label:
418 - if (!isdigit((unsigned char)*buf))
419 + if (!isdigit_l((unsigned char)*buf, loc))
423 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
424 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
428 @@ -436,8 +486,8 @@ label:
432 - if (*buf != 0 && isspace((unsigned char)*buf))
433 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
434 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
435 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
439 @@ -450,7 +500,7 @@ label:
443 - n = strtol(buf, &cp, 10);
444 + n = strtol_l(buf, &cp, 10, loc);
445 if (errno == ERANGE || (long)(t = n) != n) {
448 @@ -458,24 +508,82 @@ label:
453 + *convp = CONVERT_GMT;
459 - if (*buf == 0 || isspace((unsigned char)*buf))
460 + if (*buf == 0 || isspace_l((unsigned char)*buf, loc))
463 - if (!isdigit((unsigned char)*buf))
464 + if (!isdigit_l((unsigned char)*buf, loc))
470 + const char *savebuf = buf;
474 + for (len = 0; *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
481 + if (i64 > INT_MAX) {
487 + * Conformance requires %Y to be more then 4
488 + * digits. However, there are several cases
489 + * where %Y is immediately followed by other
490 + * digits values. So we do the conformance
491 + * case first (as many digits as possible),
492 + * and if we fail, we backup and try just 4
495 + if (len > 4 && !overflow) {
496 + struct tm savetm = *tm;
497 + int saveconv = *convp;
498 + const char *saveptr = ptr;
504 + tm->tm_year = i64 - 1900;
506 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
507 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
509 + ret = _strptime0(buf, ptr, tm, convp, loc, tm->tm_year, yday, wday);
510 + if (ret) return ret;
511 + /* Failed, so try 4-digit year */
520 +#else /* !__DARWIN_UNIX03 */
521 len = (c == 'Y') ? 4 : 2;
522 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
523 +#endif /* __DARWIN_UNIX03 */
524 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
531 +#endif /* __DARWIN_UNIX03 */
534 if (c == 'y' && i < 69)
535 @@ -483,37 +591,40 @@ label:
540 + tm->tm_year = year = i;
542 - if (*buf != 0 && isspace((unsigned char)*buf))
543 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
544 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
545 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
555 for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/}
557 - zonestr = alloca(cp - buf + 1);
558 - strncpy(zonestr, buf, cp - buf);
559 - zonestr[cp - buf] = '\0';
561 - if (0 == strcmp(zonestr, "GMT")) {
563 - } else if (0 == strcmp(zonestr, tzname[0])) {
565 - } else if (0 == strcmp(zonestr, tzname[1])) {
572 + if (len == 3 && strncmp(buf, "GMT", 3) == 0) {
573 + *convp = CONVERT_GMT;
578 + tzlen = strlen(tzname[0]);
579 + if (len == tzlen && strncmp(buf, tzname[0], tzlen) == 0) {
584 + tzlen = strlen(tzname[1]);
585 + if (len == tzlen && strncmp(buf, tzname[1], tzlen) == 0) {
596 @@ -529,7 +640,7 @@ label:
599 for (len = 4; len > 0; len--) {
600 - if (isdigit((unsigned char)*buf)) {
601 + if (isdigit_l((unsigned char)*buf, loc)) {
605 @@ -539,7 +650,7 @@ label:
607 tm->tm_hour -= sign * (i / 100);
608 tm->tm_min -= sign * (i % 100);
610 + *convp = CONVERT_GMT;
614 @@ -552,14 +663,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);