Tue Dec 1 00:03:53 2009 UTC ()
Remove __getdelim and just use getdelim.
fgetstr now works with strings up to SSIZE_MAX as a result, but may
reallocate buffers needlessly just like it used to when the buffer size
exceeds INT_MAX.
fgetstr converts errno EOVERFLOW to EINVAL on getdelim error.


(roy)
diff -r1.8 -r1.9 src/lib/libc/stdio/fgetstr.c
diff -r1.7 -r1.8 src/lib/libc/stdio/getdelim.c
diff -r1.21 -r1.22 src/lib/libc/stdio/local.h

cvs diff -r1.8 -r1.9 src/lib/libc/stdio/fgetstr.c (expand / switch to context diff)
--- src/lib/libc/stdio/fgetstr.c 2009/10/15 00:36:24 1.8
+++ src/lib/libc/stdio/fgetstr.c 2009/12/01 00:03:53 1.9
@@ -1,4 +1,4 @@
-/* $NetBSD: fgetstr.c,v 1.8 2009/10/15 00:36:24 roy Exp $	*/
+/* $NetBSD: fgetstr.c,v 1.9 2009/12/01 00:03:53 roy Exp $	*/
 
 /*
  * Copyright (c) 2009 The NetBSD Foundation, Inc.
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: fgetstr.c,v 1.8 2009/10/15 00:36:24 roy Exp $");
+__RCSID("$NetBSD: fgetstr.c,v 1.9 2009/12/01 00:03:53 roy Exp $");
 
 #include "namespace.h"
 
@@ -51,24 +51,28 @@
 {
 	char *p;
 	size_t size;
+	ssize_t n;
 
 	_DIAGASSERT(fp != NULL);
 	_DIAGASSERT(lenp != NULL);
 
 	p = (char *)fp->_lb._base;
 	size = fp->_lb._size;
-	*lenp = __getdelim(&p, &size, sep, fp);
+	n = getdelim(&p, &size, sep, fp);
 	fp->_lb._base = (unsigned char *)p;
-	/* The struct size variable is only an int ..... */
-	if (size > INT_MAX) {
+	/* The struct size variable is only an int .....
+	 * This still works when exceeded, but the buffer could be
+	 * realloced needlessly. */
+	if (size > INT_MAX)
 		fp->_lb._size = INT_MAX;
-		errno = EOVERFLOW;
-		goto error;
+	else
+		fp->_lb._size = (int)size;
+	if (n == -1) {
+		*lenp = 0;
+		if (errno == EOVERFLOW) /* fixup errno */
+			errno = EINVAL;
+		return NULL;
 	}
-	fp->_lb._size = (int)size;
-	if (*lenp != 0 && *lenp < SIZE_MAX - 1)
-		return p;
-error:
-	*lenp = 0;
-	return NULL;
+	*lenp = n;
+	return p;
 }

cvs diff -r1.7 -r1.8 src/lib/libc/stdio/getdelim.c (expand / switch to context diff)
--- src/lib/libc/stdio/getdelim.c 2009/10/25 20:44:13 1.7
+++ src/lib/libc/stdio/getdelim.c 2009/12/01 00:03:53 1.8
@@ -1,4 +1,4 @@
-/* $NetBSD: getdelim.c,v 1.7 2009/10/25 20:44:13 christos Exp $ */
+/* $NetBSD: getdelim.c,v 1.8 2009/12/01 00:03:53 roy Exp $ */
 
 /*
  * Copyright (c) 2009 The NetBSD Foundation, Inc.
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: getdelim.c,v 1.7 2009/10/25 20:44:13 christos Exp $");
+__RCSID("$NetBSD: getdelim.c,v 1.8 2009/12/01 00:03:53 roy Exp $");
 
 #include "namespace.h"
 
@@ -49,11 +49,8 @@
  * without the need for a realloc. */
 #define MINBUF	128
 
-/* This private function allows strings of upto SIZE_MAX - 2
- * and returns 0 on EOF, both of which are disallowed by POSIX.
- * Maybe this should be named fgetdelim and proposed to the OpenGroup....*/
 ssize_t
-__getdelim(char **__restrict buf, size_t *__restrict buflen,
+getdelim(char **__restrict buf, size_t *__restrict buflen,
     int sep, FILE *__restrict fp)
 {
 	unsigned char *p;
@@ -74,11 +71,12 @@
 	FLOCKFILE(fp);
 	_SET_ORIENTATION(fp, -1);
 	off = 0;
-	for (;;) {
+	do {
 		/* If the input buffer is empty, refill it */
 		if (fp->_r <= 0 && __srefill(fp)) {
 			if (__sferror(fp))
 				goto error;
+			/* No error, so EOF. */
 			break;
 		}
 
@@ -91,7 +89,7 @@
 
 		newlen = off + len + 1;
 		/* Ensure we can handle it */
-		if (newlen < off || newlen > SIZE_MAX - 2) {
+		if (newlen < off || newlen > (size_t)SSIZE_MAX + 1) {
 			errno = EOVERFLOW;
 			goto error;
 		}
@@ -124,33 +122,19 @@
 		fp->_r -= (int)len;
 		fp->_p += (int)len;
 		off += len;
-		if (p != NULL)
-			break;
-	}
+	} while (p == NULL);
 	FUNLOCKFILE(fp);
+
+	/* POSIX demands we return -1 on EOF. */
+	if (off == 0) 
+		return -1;
+
 	if (*buf != NULL)
 		*(*buf + off) = '\0';
 	return off;
 
 error:
+	fp->_flags |= __SERR;
 	FUNLOCKFILE(fp);
 	return -1;
-}
-
-ssize_t
-getdelim(char **__restrict buf, size_t *__restrict buflen,
-    int sep, FILE *__restrict fp)
-{
-	ssize_t len;
-
-	len = __getdelim(buf, buflen, sep, fp);
-	if (len == 0) {
-		/* POSIX requires that we return -1 on EOF */
-		return -1;
-	} else if (len < -1) {
-		/* POSIX requires no string larger than SSIZE_MAX */
-		errno = EOVERFLOW;
-		return -1;
-	}
-	return len;
 }

cvs diff -r1.21 -r1.22 src/lib/libc/stdio/local.h (expand / switch to context diff)
--- src/lib/libc/stdio/local.h 2009/09/24 20:38:53 1.21
+++ src/lib/libc/stdio/local.h 2009/12/01 00:03:53 1.22
@@ -1,4 +1,4 @@
-/*	$NetBSD: local.h,v 1.21 2009/09/24 20:38:53 roy Exp $	*/
+/*	$NetBSD: local.h,v 1.22 2009/12/01 00:03:53 roy Exp $	*/
 
 /*-
  * Copyright (c) 1990, 1993
@@ -75,8 +75,6 @@
 extern wint_t	__fgetwc_unlock __P((FILE *));
 extern wint_t	__fputwc_unlock __P((wchar_t, FILE *));
 
-extern ssize_t	__getdelim __P((char ** __restrict, size_t * __restrict, int,
-    FILE * __restrict));
 extern char	*__fgetstr __P((FILE * __restrict, size_t * __restrict, int));
 extern int 	 __vfwprintf_unlocked __P((FILE *, const wchar_t *,
     _BSD_VA_LIST_));