summaryrefslogtreecommitdiffstats
path: root/lib/libc/stdtime
diff options
context:
space:
mode:
authorsheldonh <sheldonh@FreeBSD.org>1999-12-08 15:49:10 +0000
committersheldonh <sheldonh@FreeBSD.org>1999-12-08 15:49:10 +0000
commit310ae47a90e189d791032e0f3a70b3443f61be72 (patch)
treefd5e88a8243cd8d97d49d52acb4c462e197051c9 /lib/libc/stdtime
parent655ca3f7fd46824cfc0c41518c9e6effac23b4d5 (diff)
downloadFreeBSD-src-310ae47a90e189d791032e0f3a70b3443f61be72.zip
FreeBSD-src-310ae47a90e189d791032e0f3a70b3443f61be72.tar.gz
Prevent digit-gobbling for all but %l and %e, which can't be fixed.
Discuss in the BUGS section of the manpage, problems involved with the use of %C, %e, %l, %p, %U and %W. PR: 13901 Reported by: scott@chronis.pobox.com
Diffstat (limited to 'lib/libc/stdtime')
-rw-r--r--lib/libc/stdtime/strptime.339
-rw-r--r--lib/libc/stdtime/strptime.c58
2 files changed, 85 insertions, 12 deletions
diff --git a/lib/libc/stdtime/strptime.3 b/lib/libc/stdtime/strptime.3
index d6aa4a2..82bc9e4 100644
--- a/lib/libc/stdtime/strptime.3
+++ b/lib/libc/stdtime/strptime.3
@@ -95,6 +95,45 @@ function appeared in
.Pp
.Sh BUGS
The
+.Fa %C
+format specifier only accepts centuries within the range 19 to 99.
+.Pp
+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,
or the value "GMT".
diff --git a/lib/libc/stdtime/strptime.c b/lib/libc/stdtime/strptime.c
index 7570381..ef1e09d 100644
--- a/lib/libc/stdtime/strptime.c
+++ b/lib/libc/stdtime/strptime.c
@@ -129,9 +129,12 @@ label:
if (!isdigit((unsigned char)*buf))
return 0;
- for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
+ /* 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;
@@ -206,9 +209,11 @@ label:
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 < 1 || i > 366)
return 0;
@@ -224,9 +229,11 @@ label:
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 == 'M') {
@@ -248,12 +255,22 @@ label:
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)
@@ -269,6 +286,10 @@ label:
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)
@@ -326,9 +347,11 @@ label:
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 > 53)
return 0;
@@ -342,10 +365,7 @@ label:
if (!isdigit((unsigned char)*buf))
return 0;
- for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) {
- i *= 10;
- i += *buf - '0';
- }
+ i = *buf - '0';
if (i > 6)
return 0;
@@ -358,12 +378,22 @@ label:
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;
@@ -414,9 +444,11 @@ label:
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;
@@ -436,9 +468,11 @@ label:
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;
OpenPOWER on IntegriCloud