Add optional 'sizehint' argument to readlines().  After approximately
this many bytes have been read, readlines stops.  Because of
buffering, the amount of bytes read is usually at least 8K more than
the hint.

Also changed read() and readline() to use PyArg_ParseTuple().

(Note that the *previous* checkin also fixed error handling and
narrowed the range of thread unblocking for all methods using
fread().)
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 3215c6e..257702f 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -431,18 +431,14 @@
 	PyFileObject *f;
 	PyObject *args;
 {
-	long bytesrequested;
+	long bytesrequested = -1;
 	size_t bytesread, buffersize, chunksize;
 	PyObject *v;
 	
 	if (f->f_fp == NULL)
 		return err_closed();
-	if (args == NULL)
-		bytesrequested = -1;
-	else {
-		if (!PyArg_Parse(args, "l", &bytesrequested))
-			return NULL;
-	}
+	if (!PyArg_ParseTuple(args, "|l", &bytesrequested))
+		return NULL;
 	if (bytesrequested < 0)
 		buffersize = new_buffersize(f, 0);
 	else
@@ -651,21 +647,16 @@
 	PyFileObject *f;
 	PyObject *args;
 {
-	int n;
+	int n = -1;
 
 	if (f->f_fp == NULL)
 		return err_closed();
-	if (args == NULL)
-		n = 0; /* Unlimited */
-	else {
-		if (!PyArg_Parse(args, "i", &n))
-			return NULL;
-		if (n == 0)
-			return PyString_FromString("");
-		if (n < 0)
-			n = 0;
-	}
-
+	if (!PyArg_ParseTuple(args, "|i", &n))
+		return NULL;
+	if (n == 0)
+		return PyString_FromString("");
+	if (n < 0)
+		n = 0;
 	return getline(f, n);
 }
 
@@ -674,6 +665,7 @@
 	PyFileObject *f;
 	PyObject *args;
 {
+	long sizehint = 0;
 	PyObject *list;
 	PyObject *line;
 	char small_buffer[SMALLCHUNK];
@@ -682,12 +674,13 @@
 	PyObject *big_buffer = NULL;
 	size_t nfilled = 0;
 	size_t nread;
+	size_t totalread = 0;
 	char *p, *q, *end;
 	int err;
 
 	if (f->f_fp == NULL)
 		return err_closed();
-	if (!PyArg_NoArgs(args))
+	if (!PyArg_ParseTuple(args, "|l", &sizehint))
 		return NULL;
 	if ((list = PyList_New(0)) == NULL)
 		return NULL;
@@ -697,6 +690,7 @@
 		nread = fread(buffer+nfilled, 1, buffersize-nfilled, f->f_fp);
 		Py_END_ALLOW_THREADS
 		if (nread == 0) {
+			sizehint = 0;
 			if (nread == 0)
 				break;
 			PyErr_SetFromErrno(PyExc_IOError);
@@ -706,6 +700,7 @@
 			list = NULL;
 			goto cleanup;
 		}
+		totalread += nread;
 		p = memchr(buffer+nfilled, '\n', nread);
 		if (p == NULL) {
 			/* Need a larger buffer to fit this line */
@@ -745,12 +740,27 @@
 		/* Move the remaining incomplete line to the start */
 		nfilled = end-q;
 		memmove(buffer, q, nfilled);
+		if (sizehint > 0)
+			if (totalread >= (size_t)sizehint)
+				break;
 	}
 	if (nfilled != 0) {
 		/* Partial last line */
 		line = PyString_FromStringAndSize(buffer, nfilled);
 		if (line == NULL)
 			goto error;
+		if (sizehint > 0) {
+			/* Need to complete the last line */
+			PyObject *rest = getline(f, 0);
+			if (rest == NULL) {
+				Py_DECREF(line);
+				goto error;
+			}
+			PyString_Concat(&line, rest);
+			Py_DECREF(rest);
+			if (line == NULL)
+				goto error;
+		}
 		err = PyList_Append(list, line);
 		Py_DECREF(line);
 		if (err != 0)
@@ -833,9 +843,9 @@
 	{"flush",	(PyCFunction)file_flush, 0},
 	{"fileno",	(PyCFunction)file_fileno, 0},
 	{"isatty",	(PyCFunction)file_isatty, 0},
-	{"read",	(PyCFunction)file_read, 0},
-	{"readline",	(PyCFunction)file_readline, 0},
-	{"readlines",	(PyCFunction)file_readlines, 0},
+	{"read",	(PyCFunction)file_read, 1},
+	{"readline",	(PyCFunction)file_readline, 1},
+	{"readlines",	(PyCFunction)file_readlines, 1},
 	{"seek",	(PyCFunction)file_seek, 0},
 #ifdef HAVE_FTRUNCATE
 	{"truncate",	(PyCFunction)file_truncate, 0},