Subject: lib/5268: bugs in strptime
To: None <gnats-bugs@gnats.netbsd.org>
From: Jochen Pohl <jpo@EasternGraphics.com>
List: netbsd-bugs
Date: 04/09/1998 00:22:57
>Number:         5268
>Category:       lib
>Synopsis:       bugs in strptime
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    lib-bug-people (Library Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Apr  8 15:35:00 1998
>Last-Modified:
>Originator:     Jochen Pohl
>Organization:
EasternGraphics GmbH
>Release:        1.3.1
>Environment:
System: NetBSD ariadne.EasternGraphics.com 1.3.1 NetBSD 1.3.1 (ARIADNE_DISKLESS) #0: Thu Apr 2 23:06:37 MEST 1998 root@ariadne.EasternGraphics.com:/usr/src/sys/arch/i386/compile/ARIADNE_DISKLESS i386

>Description:
There are several bugs in the strptime(3) function and the strptime
manual page:

1. Comparisions of month and weekday names are case sensitive. XPG4
   requires that they are case insensitive.
2. The day of the year, although in range [1, 366] in the input, should
   be stored in range [0, 365] in the tm structure. Same for the month.
3. Seconds are in range [0, 61], not [1, 61] (both in input and when
   stored in the tm structure).
4. The sentence in the manual page which claims that all ordinary
   characters are copied directly into the buffer is obviously wrong.
5. I have added a section to the manual page which describes the meaning
   of the three different types of directives in the format string in
   more detail.

>How-To-Repeat:
>Fix:

--- .%%strptime.c%%	Mon Apr  6 22:57:06 1998
+++ strptime.c	Mon Apr  6 23:22:53 1998
@@ -97,10 +97,10 @@
 again:		switch (c = *fmt++) {
 		case '%':	/* "%%" is converted to "%". */
 literal:
-		if (c != *bp++)
-			return (0);
+			if (c != *bp++)
+				return (NULL);
 
-		break;
+			break;
 
 		/*
 		 * "Alternative" modifiers. Just set the appropriate flag
@@ -170,12 +170,12 @@
 			for (i = 0; i < 7; i++) {
 				/* Full name. */
 				len = strlen(_ctloc(day[i]));
-				if (strncmp(_ctloc(day[i]), bp, len) == 0)
+				if (strncasecmp(_ctloc(day[i]), bp, len) == 0)
 					break;
 
 				/* Abbreviated name. */
 				len = strlen(_ctloc(abday[i]));
-				if (strncmp(_ctloc(abday[i]), bp, len) == 0)
+				if (strncasecmp(_ctloc(abday[i]), bp, len) == 0)
 					break;
 			}
 
@@ -194,12 +194,12 @@
 			for (i = 0; i < 12; i++) {
 				/* Full name. */
 				len = strlen(_ctloc(mon[i]));
-				if (strncmp(_ctloc(mon[i]), bp, len) == 0)
+				if (strncasecmp(_ctloc(mon[i]), bp, len) == 0)
 					break;
 
 				/* Abbreviated name. */
 				len = strlen(_ctloc(abmon[i]));
-				if (strncmp(_ctloc(abmon[i]), bp, len) == 0)
+				if (strncasecmp(_ctloc(abmon[i]), bp, len) == 0)
 					break;
 			}
 
@@ -248,6 +248,7 @@
 			_LEGAL_ALT(0);
 			if (!(_conv_num(&bp, &tm->tm_yday, 1, 366)))
 				return (0);
+			tm->tm_yday--;
 			break;
 
 		case 'M':	/* The minute. */
@@ -260,6 +261,7 @@
 			_LEGAL_ALT(_ALT_O);
 			if (!(_conv_num(&bp, &tm->tm_mon, 1, 12)))
 				return (0);
+			tm->tm_mon--;
 			break;
 
 		case 'p':	/* The locale's equivalent of AM/PM. */
@@ -290,7 +292,7 @@
 
 		case 'S':	/* The seconds. */
 			_LEGAL_ALT(_ALT_O);
-			if (!(_conv_num(&bp, &tm->tm_sec, 1, 61)))
+			if (!(_conv_num(&bp, &tm->tm_sec, 0, 61)))
 				return (0);
 			break;
 
--- .%%strptime.3%%	Mon Apr  6 23:22:59 1998
+++ strptime.3	Thu Apr  9 00:04:02 1998
@@ -45,7 +45,7 @@
 .Fn strptime "const char *buf" "const char *format" "struct tm *tm"
 .Sh DESCRIPTION
 The
-.Nm
+.Fn strptime
 function converts the character string pointed to by
 .Fa buf
 to values which are stored in the ``tm'' structure pointed to by
@@ -55,9 +55,11 @@
 .Pp
 The
 .Fa format
-string consists of zero or more conversion specifications and
-ordinary characters.  All ordinary characters are copied directly into
-the buffer.  A conversion specification consists of a percent sign `%'
+string consists of zero or more directives. A directive is composed
+of either one or more white-space as defined by
+.Fn isspace ,
+an ordinary character (neither `%' nor a white-space), or a conversion
+specification. A conversion specification consists of a percent sign `%'
 followed by one or two conversion characters which specify the replacement
 required. There must be white-space or other non-alphanumeric characters
 between any two conversion specifications.
@@ -165,13 +167,39 @@
 conversion specification. As there are currently neither alternative formats
 nor specifications supported by the system, the behavior will be as if the
 unmodified conversion specification were used.
+.Ss General Specifications
+A directive consisting of %n, %t, white-space characters or any
+combination thereof matches any amount of white-space characters,
+including none, in the input.
+.Pp
+A directive that is an ordinary character matches the same ordinary
+character in the input. If the ordinary character can't be matched
+the
+.Fn strptime
+function fails.
+.Pp
+Any other conversion specification matches all characters until the
+first character which matches the next conversion specification. These
+characters (excluding the character matching the next conversion
+specification) are compared to the values of the current locale
+associated with the conversion specification. If a match is found,
+appropriate members of the ``tm'' structure pointed to by
+.Fa tm
+are filled with values corresponding to the locale information.
+Case is ignored when matching string items in
+.Fa buf ,
+such as month and weekday names. If no match is found the
+.Fn strptime
+function fails.
 .Sh RETURN VALUES
 If successful, the
-.Nm
+.Fn strptime
 function returns a pointer to the character following the last character
 parsed. Otherwise, a null pointer is returned.
 .Sh SEE ALSO
-.Xr strftime 3
+.Xr scanf 3 ,
+.Xr strftime 3 ,
+.Xr time 3
 .Sh STANDARDS
 The
 .Fn strptime
>Audit-Trail:
>Unformatted: