summaryrefslogtreecommitdiff
path: root/lib/libc
diff options
context:
space:
mode:
authorSheldon Hearn <sheldonh@FreeBSD.org>1999-12-09 08:54:32 +0000
committerSheldon Hearn <sheldonh@FreeBSD.org>1999-12-09 08:54:32 +0000
commitafbfd4ddc45e20c871ba513154a736aba1eedb5f (patch)
treef6c268850cb1de8c3abfa9cf260153b6a53b9fc4 /lib/libc
parent9a3551c26b88867696bd78e008f64b930c2a15ed (diff)
Notes
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/stdtime/strptime.335
-rw-r--r--lib/libc/stdtime/strptime.c208
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;
}