SF patch #100740: Add optional size arguments to .readline() and
.readlines() methods.  Inspired by a patch from Wolfgang Grafen,
though this version of the patch was completely rewritten from his
code.
diff --git a/Lib/gzip.py b/Lib/gzip.py
index 43501d4..0c9642b 100644
--- a/Lib/gzip.py
+++ b/Lib/gzip.py
@@ -5,10 +5,8 @@
 
 # based on Andrew Kuchling's minigzip.py distributed with the zlib module
 
-import time
-import string
+import string, struct, sys, time
 import zlib
-import struct
 import __builtin__
 
 FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16
@@ -175,7 +173,8 @@
         if self.fileobj is None: raise EOFError, "Reached EOF"
  	
         if self._new_member:
-            # If the _new_member flag is set, we have to 
+            # If the _new_member flag is set, we have to
+            # jump to the next member, if there is one.
             # 
             # First, check if we're at the end of the file;
             # if so, it's time to stop; no more members to read.
@@ -273,27 +272,46 @@
     def isatty(self):
         return 0
 
-    def readline(self):
+    def readline(self, size=-1):
+        if size < 0: size = sys.maxint
         bufs = []
-        readsize = 100
+        orig_size = size
+        readsize = min(100, size)    # Read from the file in small chunks
         while 1:
+            if size == 0:
+                return string.join(bufs, '') # Return resulting line
+
             c = self.read(readsize)
             i = string.find(c, '\n')
-            if i >= 0 or c == '':
-                bufs.append(c[:i+1])
-                self._unread(c[i+1:])
-                return string.join(bufs, '')
-            bufs.append(c)
-            readsize = readsize * 2
+            if size is not None:
+                # We set i=size to break out of the loop under two
+                # conditions: 1) there's no newline, and the chunk is 
+                # larger than size, or 2) there is a newline, but the
+                # resulting line would be longer than 'size'.
+                if i==-1 and len(c) > size: i=size-1
+                elif size <= i: i = size -1
 
-    def readlines(self, ignored=None):
-        buf = self.read()
-        lines = string.split(buf, '\n')
-        for i in range(len(lines)-1):
-            lines[i] = lines[i] + '\n'
-        if lines and not lines[-1]:
-            del lines[-1]
-        return lines
+            if i >= 0 or c == '':
+                bufs.append(c[:i+1])    # Add portion of last chunk
+                self._unread(c[i+1:])   # Push back rest of chunk
+                return string.join(bufs, '') # Return resulting line
+
+            # Append chunk to list, decrease 'size',
+            bufs.append(c)
+            size = size - len(c)
+            readsize = min(size, readsize * 2)
+            
+    def readlines(self, sizehint=0):
+        # Negative numbers result in reading all the lines
+        if sizehint <= 0: sizehint = sys.maxint
+        L = []
+        while sizehint > 0:
+            line = self.readline()
+            if line == "": break
+            L.append( line )
+            sizehint = sizehint - len(line)
+
+        return L
 
     def writelines(self, L):
         for line in L: