diff options
| author | Sheldon Hearn <sheldonh@FreeBSD.org> | 1999-12-09 08:54:32 +0000 |
|---|---|---|
| committer | Sheldon Hearn <sheldonh@FreeBSD.org> | 1999-12-09 08:54:32 +0000 |
| commit | afbfd4ddc45e20c871ba513154a736aba1eedb5f (patch) | |
| tree | f6c268850cb1de8c3abfa9cf260153b6a53b9fc4 /lib/libc | |
| parent | 9a3551c26b88867696bd78e008f64b930c2a15ed (diff) | |
Notes
Diffstat (limited to 'lib/libc')
| -rw-r--r-- | lib/libc/stdtime/strptime.3 | 35 | ||||
| -rw-r--r-- | lib/libc/stdtime/strptime.c | 208 |
2 files changed, 204 insertions, 39 deletions
diff --git a/lib/libc/stdtime/strptime.3 b/lib/libc/stdtime/strptime.3 index d6aa4a276941..c93dc8994fee 100644 --- a/lib/libc/stdtime/strptime.3 +++ b/lib/libc/stdtime/strptime.3 @@ -94,6 +94,41 @@ function appeared in .Fx 3.0 . .Pp .Sh BUGS +Both the +.Fa %e +and +.Fa %l +format specifiers may incorrectly scan one too many digits +if the intended values comprise only a single digit +and that digit is followed immediately by another digit. +Both specifiers accept zero-padded values, +even though they are both defined as taking unpadded values. +.Pp +The +.Fa %p +format specifier has no effect unless it is parsed +.Em after +hour-related specifiers. +Specifying +.Fa %l +without +.Fa %p +will produce undefined results. +Note that 12AM +.Pq ante meridiem +is taken as midnight +and 12PM +.Pq post meridiem +is taken as noon. +.Pp +The +.Fa %U +and +.Fa %W +format specifiers accept any value within the range 00 to 53 +without validating against other values supplied (like month +or day of the year, for example). +.Pp The .Fa %Z format specifier only accepts time zone abbreviations of the local time zone, diff --git a/lib/libc/stdtime/strptime.c b/lib/libc/stdtime/strptime.c index 43145637a14b..ef1e09d76a9f 100644 --- a/lib/libc/stdtime/strptime.c +++ b/lib/libc/stdtime/strptime.c @@ -90,6 +90,7 @@ _strptime(const char *buf, const char *fmt, struct tm *tm) const char *ptr; int i, len; + int Ealternative, Oalternative; ptr = fmt; while (*ptr != 0) { @@ -107,6 +108,9 @@ _strptime(const char *buf, const char *fmt, struct tm *tm) continue; } + Ealternative = 0; + Oalternative = 0; +label: c = *ptr++; switch (c) { case 0: @@ -115,14 +119,31 @@ _strptime(const char *buf, const char *fmt, struct tm *tm) return 0; break; - case 'C': + case '+': buf = _strptime(buf, Locale->date_fmt, tm); if (buf == 0) return 0; break; + case 'C': + if (!isdigit((unsigned char)*buf)) + return 0; + + /* XXX This will break for 3-digit centuries. */ + len = 2; + for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + i *= 10; + i += *buf - '0'; + len--; + } + if (i < 19) + return 0; + + tm->tm_year = i * 100 - 1900; + break; + case 'c': - buf = _strptime(buf, "%x %X", tm); + buf = _strptime(buf, Locale->c_fmt, tm); if (buf == 0) return 0; break; @@ -133,6 +154,27 @@ _strptime(const char *buf, const char *fmt, struct tm *tm) return 0; break; + case 'E': + if (Ealternative || Oalternative) + break; + Ealternative++; + goto label; + + case 'O': + if (Ealternative || Oalternative) + break; + Oalternative++; + goto label; + + case 'F': + case 'f': + if (!Ealternative) + break; + buf = _strptime(buf, (c == 'f') ? Locale->Ef_fmt : Locale->EF_fmt, tm); + if (buf == 0) + return 0; + break; + case 'R': buf = _strptime(buf, "%H:%M", tm); if (buf == 0) @@ -167,14 +209,16 @@ _strptime(const char *buf, const char *fmt, struct tm *tm) if (!isdigit((unsigned char)*buf)) return 0; - for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { + len = 3; + for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { i *= 10; i += *buf - '0'; + len--; } - if (i > 365) + if (i < 1 || i > 366) return 0; - tm->tm_yday = i; + tm->tm_yday = i - 1; break; case 'M': @@ -185,17 +229,22 @@ _strptime(const char *buf, const char *fmt, struct tm *tm) if (!isdigit((unsigned char)*buf)) return 0; - for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { + len = 2; + for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { i *= 10; i += *buf - '0'; + len--; } - if (i > 59) - return 0; - if (c == 'M') + if (c == 'M') { + if (i > 59) + return 0; tm->tm_min = i; - else + } else { + if (i > 60) + return 0; tm->tm_sec = i; + } if (*buf != 0 && isspace((unsigned char)*buf)) while (*ptr != 0 && !isspace((unsigned char)*ptr)) @@ -206,17 +255,27 @@ _strptime(const char *buf, const char *fmt, struct tm *tm) case 'I': case 'k': case 'l': + /* + * Of these, %l is the only specifier explicitly + * documented as not being zero-padded. However, + * there is no harm in allowing zero-padding. + * + * XXX The %l specifier may gobble one too many + * digits if used incorrectly. + */ if (!isdigit((unsigned char)*buf)) return 0; - for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { + len = 2; + for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { i *= 10; i += *buf - '0'; + len--; } if (c == 'H' || c == 'k') { if (i > 23) return 0; - } else if (i > 11) + } else if (i > 12) return 0; tm->tm_hour = i; @@ -227,6 +286,10 @@ _strptime(const char *buf, const char *fmt, struct tm *tm) break; case 'p': + /* + * XXX This is bogus if parsed before hour-related + * specifiers. + */ len = strlen(Locale->am); if (strncasecmp(buf, Locale->am, len) == 0) { if (tm->tm_hour > 12) @@ -252,17 +315,19 @@ _strptime(const char *buf, const char *fmt, struct tm *tm) case 'A': case 'a': for (i = 0; i < asizeof(Locale->weekday); i++) { - len = strlen(Locale->weekday[i]); - if (strncasecmp(buf, - Locale->weekday[i], - len) == 0) - break; - - len = strlen(Locale->wday[i]); - if (strncasecmp(buf, - Locale->wday[i], - len) == 0) - break; + if (c == 'A') { + len = strlen(Locale->weekday[i]); + if (strncasecmp(buf, + Locale->weekday[i], + len) == 0) + break; + } else { + len = strlen(Locale->wday[i]); + if (strncasecmp(buf, + Locale->wday[i], + len) == 0) + break; + } } if (i == asizeof(Locale->weekday)) return 0; @@ -271,14 +336,64 @@ _strptime(const char *buf, const char *fmt, struct tm *tm) buf += len; break; + case 'U': + case 'W': + /* + * XXX This is bogus, as we can not assume any valid + * information present in the tm structure at this + * point to calculate a real value, so just check the + * range for now. + */ + if (!isdigit((unsigned char)*buf)) + return 0; + + len = 2; + for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + i *= 10; + i += *buf - '0'; + len--; + } + if (i > 53) + return 0; + + if (*buf != 0 && isspace((unsigned char)*buf)) + while (*ptr != 0 && !isspace((unsigned char)*ptr)) + ptr++; + break; + + case 'w': + if (!isdigit((unsigned char)*buf)) + return 0; + + i = *buf - '0'; + if (i > 6) + return 0; + + tm->tm_wday = i; + + if (*buf != 0 && isspace((unsigned char)*buf)) + while (*ptr != 0 && !isspace((unsigned char)*ptr)) + ptr++; + break; + case 'd': case 'e': + /* + * The %e specifier is explicitly documented as not + * being zero-padded but there is no harm in allowing + * such padding. + * + * XXX The %e specifier may gobble one too many + * digits if used incorrectly. + */ if (!isdigit((unsigned char)*buf)) return 0; - for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { + len = 2; + for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { i *= 10; i += *buf - '0'; + len--; } if (i > 31) return 0; @@ -294,17 +409,29 @@ _strptime(const char *buf, const char *fmt, struct tm *tm) case 'b': case 'h': for (i = 0; i < asizeof(Locale->month); i++) { - len = strlen(Locale->month[i]); - if (strncasecmp(buf, - Locale->month[i], - len) == 0) - break; - - len = strlen(Locale->mon[i]); - if (strncasecmp(buf, - Locale->mon[i], - len) == 0) - break; + if (Oalternative) { + if (c == 'B') { + len = strlen(Locale->alt_month[i]); + if (strncasecmp(buf, + Locale->alt_month[i], + len) == 0) + break; + } + } else { + if (c == 'B') { + len = strlen(Locale->month[i]); + if (strncasecmp(buf, + Locale->month[i], + len) == 0) + break; + } else { + len = strlen(Locale->mon[i]); + if (strncasecmp(buf, + Locale->mon[i], + len) == 0) + break; + } + } } if (i == asizeof(Locale->month)) return 0; @@ -317,9 +444,11 @@ _strptime(const char *buf, const char *fmt, struct tm *tm) if (!isdigit((unsigned char)*buf)) return 0; - for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { + len = 2; + for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { i *= 10; i += *buf - '0'; + len--; } if (i < 1 || i > 12) return 0; @@ -339,9 +468,11 @@ _strptime(const char *buf, const char *fmt, struct tm *tm) if (!isdigit((unsigned char)*buf)) return 0; - for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { + len = (c == 'Y') ? 4 : 2; + for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { i *= 10; i += *buf - '0'; + len--; } if (c == 'Y') i -= 1900; @@ -362,7 +493,7 @@ _strptime(const char *buf, const char *fmt, struct tm *tm) const char *cp; char *zonestr; - for (cp = buf; *cp && isupper(*cp); ++cp) {/*empty*/} + for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/} if (cp - buf) { zonestr = alloca(cp - buf + 1); strncpy(zonestr, buf, cp - buf); @@ -383,7 +514,6 @@ _strptime(const char *buf, const char *fmt, struct tm *tm) break; } } - return (char *)buf; } |
