diff options
author | sheldonh <sheldonh@FreeBSD.org> | 1999-12-08 15:49:10 +0000 |
---|---|---|
committer | sheldonh <sheldonh@FreeBSD.org> | 1999-12-08 15:49:10 +0000 |
commit | 310ae47a90e189d791032e0f3a70b3443f61be72 (patch) | |
tree | fd5e88a8243cd8d97d49d52acb4c462e197051c9 /lib | |
parent | 655ca3f7fd46824cfc0c41518c9e6effac23b4d5 (diff) | |
download | FreeBSD-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')
-rw-r--r-- | lib/libc/stdtime/strptime.3 | 39 | ||||
-rw-r--r-- | lib/libc/stdtime/strptime.c | 58 |
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; |