--- strptime.c.orig 2004-11-25 11:38:45.000000000 -0800 +++ strptime.c 2005-02-24 01:09:32.000000000 -0800 @@ -61,6 +61,8 @@ #endif /* not lint */ __FBSDID("$FreeBSD: src/lib/libc/stdtime/strptime.c,v 1.35 2003/11/17 04:19:15 nectar Exp $"); +#include "xlocale_private.h" + #include "namespace.h" #include <time.h> #include <ctype.h> @@ -72,19 +74,19 @@ #include "libc_private.h" #include "timelocal.h" -static char * _strptime(const char *, const char *, struct tm *, int *); +static char * _strptime(const char *, const char *, struct tm *, int *, locale_t); #define asizeof(a) (sizeof (a) / sizeof ((a)[0])) static char * -_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp) +_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp, locale_t loc) { char c; const char *ptr; int i, len; int Ealternative, Oalternative; - struct lc_time_T *tptr = __get_current_time_locale(); + struct lc_time_T *tptr = __get_current_time_locale(loc); ptr = fmt; while (*ptr != 0) { @@ -94,8 +96,8 @@ c = *ptr++; if (c != '%') { - if (isspace((unsigned char)c)) - while (*buf != 0 && isspace((unsigned char)*buf)) + if (isspace_l((unsigned char)c, loc)) + while (*buf != 0 && isspace_l((unsigned char)*buf, loc)) buf++; else if (c != *buf++) return 0; @@ -114,18 +116,18 @@ break; case '+': - buf = _strptime(buf, tptr->date_fmt, tm, GMTp); + buf = _strptime(buf, tptr->date_fmt, tm, GMTp, loc); if (buf == 0) return 0; break; case 'C': - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, loc)) return 0; /* XXX This will break for 3-digit centuries. */ len = 2; - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) { i *= 10; i += *buf - '0'; len--; @@ -137,13 +139,13 @@ break; case 'c': - buf = _strptime(buf, tptr->c_fmt, tm, GMTp); + buf = _strptime(buf, tptr->c_fmt, tm, GMTp, loc); if (buf == 0) return 0; break; case 'D': - buf = _strptime(buf, "%m/%d/%y", tm, GMTp); + buf = _strptime(buf, "%m/%d/%y", tm, GMTp, loc); if (buf == 0) return 0; break; @@ -161,47 +163,47 @@ goto label; case 'F': - buf = _strptime(buf, "%Y-%m-%d", tm, GMTp); + buf = _strptime(buf, "%Y-%m-%d", tm, GMTp, loc); if (buf == 0) return 0; break; case 'R': - buf = _strptime(buf, "%H:%M", tm, GMTp); + buf = _strptime(buf, "%H:%M", tm, GMTp, loc); if (buf == 0) return 0; break; case 'r': - buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp); + buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp, loc); if (buf == 0) return 0; break; case 'T': - buf = _strptime(buf, "%H:%M:%S", tm, GMTp); + buf = _strptime(buf, "%H:%M:%S", tm, GMTp, loc); if (buf == 0) return 0; break; case 'X': - buf = _strptime(buf, tptr->X_fmt, tm, GMTp); + buf = _strptime(buf, tptr->X_fmt, tm, GMTp, loc); if (buf == 0) return 0; break; case 'x': - buf = _strptime(buf, tptr->x_fmt, tm, GMTp); + buf = _strptime(buf, tptr->x_fmt, tm, GMTp, loc); if (buf == 0) return 0; break; case 'j': - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, loc)) return 0; len = 3; - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) { i *= 10; i += *buf - '0'; len--; @@ -214,14 +216,14 @@ case 'M': case 'S': - if (*buf == 0 || isspace((unsigned char)*buf)) + if (*buf == 0 || isspace_l((unsigned char)*buf, loc)) break; - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, loc)) return 0; len = 2; - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) { i *= 10; i += *buf - '0'; len--; @@ -237,8 +239,8 @@ tm->tm_sec = i; } - if (*buf != 0 && isspace((unsigned char)*buf)) - while (*ptr != 0 && !isspace((unsigned char)*ptr)) + if (*buf != 0 && isspace_l((unsigned char)*buf, loc)) + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc)) ptr++; break; @@ -254,11 +256,11 @@ * XXX The %l specifier may gobble one too many * digits if used incorrectly. */ - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, loc)) return 0; len = 2; - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) { i *= 10; i += *buf - '0'; len--; @@ -271,8 +273,8 @@ tm->tm_hour = i; - if (*buf != 0 && isspace((unsigned char)*buf)) - while (*ptr != 0 && !isspace((unsigned char)*ptr)) + if (*buf != 0 && isspace_l((unsigned char)*buf, loc)) + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc)) ptr++; break; @@ -282,7 +284,7 @@ * specifiers. */ len = strlen(tptr->am); - if (strncasecmp(buf, tptr->am, len) == 0) { + if (strncasecmp_l(buf, tptr->am, len, loc) == 0) { if (tm->tm_hour > 12) return 0; if (tm->tm_hour == 12) @@ -292,7 +294,7 @@ } len = strlen(tptr->pm); - if (strncasecmp(buf, tptr->pm, len) == 0) { + if (strncasecmp_l(buf, tptr->pm, len, loc) == 0) { if (tm->tm_hour > 12) return 0; if (tm->tm_hour != 12) @@ -307,12 +309,12 @@ case 'a': for (i = 0; i < asizeof(tptr->weekday); i++) { len = strlen(tptr->weekday[i]); - if (strncasecmp(buf, tptr->weekday[i], - len) == 0) + if (strncasecmp_l(buf, tptr->weekday[i], + len, loc) == 0) break; len = strlen(tptr->wday[i]); - if (strncasecmp(buf, tptr->wday[i], - len) == 0) + if (strncasecmp_l(buf, tptr->wday[i], + len, loc) == 0) break; } if (i == asizeof(tptr->weekday)) @@ -330,11 +332,11 @@ * point to calculate a real value, so just check the * range for now. */ - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, loc)) return 0; len = 2; - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) { i *= 10; i += *buf - '0'; len--; @@ -342,13 +344,13 @@ if (i > 53) return 0; - if (*buf != 0 && isspace((unsigned char)*buf)) - while (*ptr != 0 && !isspace((unsigned char)*ptr)) + if (*buf != 0 && isspace_l((unsigned char)*buf, loc)) + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc)) ptr++; break; case 'w': - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, loc)) return 0; i = *buf - '0'; @@ -357,8 +359,8 @@ tm->tm_wday = i; - if (*buf != 0 && isspace((unsigned char)*buf)) - while (*ptr != 0 && !isspace((unsigned char)*ptr)) + if (*buf != 0 && isspace_l((unsigned char)*buf, loc)) + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc)) ptr++; break; @@ -372,11 +374,11 @@ * XXX The %e specifier may gobble one too many * digits if used incorrectly. */ - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, loc)) return 0; len = 2; - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) { i *= 10; i += *buf - '0'; len--; @@ -386,8 +388,8 @@ tm->tm_mday = i; - if (*buf != 0 && isspace((unsigned char)*buf)) - while (*ptr != 0 && !isspace((unsigned char)*ptr)) + if (*buf != 0 && isspace_l((unsigned char)*buf, loc)) + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc)) ptr++; break; @@ -398,19 +400,19 @@ if (Oalternative) { if (c == 'B') { len = strlen(tptr->alt_month[i]); - if (strncasecmp(buf, + if (strncasecmp_l(buf, tptr->alt_month[i], - len) == 0) + len, loc) == 0) break; } } else { len = strlen(tptr->month[i]); - if (strncasecmp(buf, tptr->month[i], - len) == 0) + if (strncasecmp_l(buf, tptr->month[i], + len, loc) == 0) break; len = strlen(tptr->mon[i]); - if (strncasecmp(buf, tptr->mon[i], - len) == 0) + if (strncasecmp_l(buf, tptr->mon[i], + len, loc) == 0) break; } } @@ -422,11 +424,11 @@ break; case 'm': - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, loc)) return 0; len = 2; - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) { i *= 10; i += *buf - '0'; len--; @@ -436,8 +438,8 @@ tm->tm_mon = i - 1; - if (*buf != 0 && isspace((unsigned char)*buf)) - while (*ptr != 0 && !isspace((unsigned char)*ptr)) + if (*buf != 0 && isspace_l((unsigned char)*buf, loc)) + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc)) ptr++; break; @@ -450,7 +452,7 @@ sverrno = errno; errno = 0; - n = strtol(buf, &cp, 10); + n = strtol_l(buf, &cp, 10, loc); if (errno == ERANGE || (long)(t = n) != n) { errno = sverrno; return 0; @@ -464,14 +466,14 @@ case 'Y': case 'y': - if (*buf == 0 || isspace((unsigned char)*buf)) + if (*buf == 0 || isspace_l((unsigned char)*buf, loc)) break; - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, loc)) return 0; len = (c == 'Y') ? 4 : 2; - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) { i *= 10; i += *buf - '0'; len--; @@ -485,8 +487,8 @@ tm->tm_year = i; - if (*buf != 0 && isspace((unsigned char)*buf)) - while (*ptr != 0 && !isspace((unsigned char)*ptr)) + if (*buf != 0 && isspace_l((unsigned char)*buf, loc)) + while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc)) ptr++; break; @@ -495,7 +497,7 @@ const char *cp; char *zonestr; - for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/} + for (cp = buf; *cp && isupper_l((unsigned char)*cp, loc); ++cp) {/*empty*/} if (cp - buf) { zonestr = alloca(cp - buf + 1); strncpy(zonestr, buf, cp - buf); @@ -528,7 +530,25 @@ int gmt; gmt = 0; - ret = _strptime(buf, fmt, tm, &gmt); + ret = _strptime(buf, fmt, tm, &gmt, __current_locale()); + if (ret && gmt) { + time_t t = timegm(tm); + localtime_r(&t, tm); + } + + return (ret); +} + +char * +strptime_l(const char * __restrict buf, const char * __restrict fmt, + struct tm * __restrict tm, locale_t loc) +{ + char *ret; + int gmt; + + NORMALIZE_LOCALE(loc); + gmt = 0; + ret = _strptime(buf, fmt, tm, &gmt, loc); if (ret && gmt) { time_t t = timegm(tm); localtime_r(&t, tm);