1 --- strptime.c.orig 2008-04-24 01:10:36.000000000 -0700
2 +++ strptime.c 2008-04-24 02:01:31.000000000 -0700
3 @@ -61,10 +61,13 @@ 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"
17 @@ -72,30 +75,41 @@ __FBSDID("$FreeBSD: src/lib/libc/stdtime
18 #include "libc_private.h"
19 #include "timelocal.h"
21 -static char * _strptime(const char *, const char *, struct tm *, int *);
22 +static char * _strptime(const char *, const char *, struct tm *, int *, locale_t) __DARWIN_ALIAS(_strptime);
23 +time_t _mktime(struct tm *, const char *);
25 #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
27 +enum {CONVERT_NONE, CONVERT_GMT, CONVERT_ZONE};
30 -_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp)
31 +_strptime(const char *buf, const char *fmt, struct tm *tm, int *convp, locale_t loc)
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) ? 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,37 @@ 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))
469 + for (i = 0; *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
475 +#else /* !__DARWIN_UNIX03 */
476 len = (c == 'Y') ? 4 : 2;
477 - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
478 +#endif /* __DARWIN_UNIX03 */
479 + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
486 +#endif /* __DARWIN_UNIX03 */
489 if (c == 'y' && i < 69)
490 @@ -483,35 +546,58 @@ label:
495 + tm->tm_year = year = i;
497 - if (*buf != 0 && isspace((unsigned char)*buf))
498 - while (*ptr != 0 && !isspace((unsigned char)*ptr))
499 + if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
500 + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
510 for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/}
512 - zonestr = alloca(cp - buf + 1);
513 - strncpy(zonestr, buf, cp - buf);
514 - zonestr[cp - buf] = '\0';
516 - if (0 == strcmp(zonestr, "GMT")) {
518 - } else if (0 == strcmp(zonestr, tzname[0])) {
520 - } else if (0 == strcmp(zonestr, tzname[1])) {
527 + if (len == 3 && strncmp(buf, "GMT", 3) == 0) {
528 + *convp = CONVERT_GMT;
533 + tzlen = strlen(tzname[0]);
534 + if (len == tzlen && strncmp(buf, tzname[0], tzlen) == 0) {
539 + tzlen = strlen(tzname[1]);
540 + if (len == tzlen && strncmp(buf, tzname[1], tzlen) == 0) {
553 + if ((buf[0] != '+' && buf[0] != '-')
554 + || !isdigit_l((unsigned char)buf[1], loc)
555 + || !isdigit_l((unsigned char)buf[2], loc)
556 + || !isdigit_l((unsigned char)buf[3], loc)
557 + || !isdigit_l((unsigned char)buf[4], loc))
559 + sscanf(buf, "%c%2d%2d", &sign, &hr, &min);
560 + *convp = CONVERT_ZONE;
561 + tm->tm_gmtoff = 60 * (60 * hr + min);
563 + tm->tm_gmtoff = -tm->tm_gmtoff;
568 @@ -524,14 +610,39 @@ char *
569 strptime(const char * __restrict buf, const char * __restrict fmt,
570 struct tm * __restrict tm)
572 + return strptime_l(buf, fmt, tm, __current_locale());
575 +extern time_t timeoff(struct tm *, long);
578 +strptime_l(const char * __restrict buf, const char * __restrict fmt,
579 + struct tm * __restrict tm, locale_t loc)
586 - ret = _strptime(buf, fmt, tm, &gmt);
588 - time_t t = timegm(tm);
589 - localtime_r(&t, tm);
590 + NORMALIZE_LOCALE(loc);
591 + conv = CONVERT_NONE;
592 + tm->tm_zone = NULL;
593 + ret = _strptime(buf, fmt, tm, &conv, loc);
600 + localtime_r(&t, tm);
604 + long offset = tm->tm_gmtoff;
606 + t = timeoff(tm, offset);
607 + localtime_r(&t, tm);