Author: Armin Rigo <[email protected]>
Branch: fileops2
Changeset: r67207:3a0aea85c508
Date: 2013-10-08 16:55 +0200
http://bitbucket.org/pypy/pypy/changeset/3a0aea85c508/

Log:    Finish the implementation of readline().

diff --git a/rpython/rlib/rfile.py b/rpython/rlib/rfile.py
--- a/rpython/rlib/rfile.py
+++ b/rpython/rlib/rfile.py
@@ -47,7 +47,7 @@
                      rffi.CCHARP)
 
 BASE_BUF_SIZE = 4096
-BASE_LINE_SIZE = 1000
+BASE_LINE_SIZE = 100
 
 def create_file(filename, mode="r", buffering=-1):
     assert buffering == -1
@@ -194,35 +194,48 @@
     def __del__(self):
         self.close()
 
+    def _readline1(self, raw_buf):
+        result = c_fgets(raw_buf, BASE_LINE_SIZE, self.ll_file)
+        if not result:
+            if c_feof(self.ll_file):   # ok
+                return 0
+            errno = c_ferror(self.ll_file)
+            raise OSError(errno, os.strerror(errno))
+        #
+        # Assume that fgets() works as documented, and additionally
+        # never writes beyond the final \0, which the CPython
+        # fileobject.c says appears to be the case everywhere.
+        # The only case where the buffer was not big enough is the
+        # case where the buffer is full, ends with \0, and doesn't
+        # end with \n\0.
+        strlen = 0
+        while raw_buf[strlen] != '\0':
+            strlen += 1
+        if (strlen == BASE_LINE_SIZE - 1 and
+              raw_buf[BASE_LINE_SIZE - 2] != '\n'):
+            return -1    # overflow!
+        # common case
+        return strlen
+
     def readline(self):
         if self.ll_file:
             raw_buf, gc_buf = rffi.alloc_buffer(BASE_LINE_SIZE)
             try:
-                result = c_fgets(raw_buf, BASE_LINE_SIZE, self.ll_file)
-                if not result:
-                    if c_feof(self.ll_file):   # ok
-                        return ''
-                    errno = c_ferror(self.ll_file)
-                    raise OSError(errno, os.strerror(errno))
+                c = self._readline1(raw_buf)
+                if c >= 0:
+                    return rffi.str_from_buffer(raw_buf, gc_buf,
+                                                BASE_LINE_SIZE, c)
                 #
-                # Assume that fgets() works as documented, and additionally
-                # never writes beyond the final \0, which the CPython
-                # fileobject.c says appears to be the case everywhere.
-                # The only case where the buffer was not big enough is the
-                # case where the buffer is full, ends with \0, and doesn't
-                # end with \n\0.
-                strlen = 0
-                while raw_buf[strlen] != '\0':
-                    strlen += 1
+                # this is the rare case: the line is longer than BASE_LINE_SIZE
+                s = StringBuilder()
+                while True:
+                    s.append_charpsize(raw_buf, BASE_LINE_SIZE - 1)
+                    c = self._readline1(raw_buf)
+                    if c >= 0:
+                        break
                 #
-                if (strlen != BASE_LINE_SIZE - 1 or
-                      raw_buf[BASE_LINE_SIZE - 2] == '\n'):
-                    # common case
-                    return rffi.str_from_buffer(raw_buf, gc_buf,
-                                                BASE_LINE_SIZE, strlen)
-                #
-                XXX
-
+                s.append_charpsize(raw_buf, c)
+                return s.build()
             finally:
                 rffi.keep_buffer_alive_until_here(raw_buf, gc_buf)
         raise ValueError("I/O operation on closed file")
diff --git a/rpython/rlib/test/test_rfile.py b/rpython/rlib/test/test_rfile.py
--- a/rpython/rlib/test/test_rfile.py
+++ b/rpython/rlib/test/test_rfile.py
@@ -147,15 +147,30 @@
         j = 0
         expected = []
         with open(fname, 'w') as f:
-            for i in range(50):
-                s = ''.join([chr(32+(k&63)) for k in range(j, j + i*7)])
+            for i in range(150):
+                s = ''.join([chr(32+(k&63)) for k in range(j, j + i)])
+                j += 1
                 print >> f, s
-            f.write('no newline')
         expected = open(fname).readlines()
+        expected += ['', '']
+        assert len(expected) == 152
 
         f = rfile.create_file(fname, 'r')
-        got = []
-        for j in range(53):
-            got.append(f.readline())
+        for j in range(152):
+            got = f.readline()
+            assert got == expected[j]
         f.close()
-        assert got == expected + ['', '']
+
+    def test_readline_without_eol_at_the_end(self):
+        fname = str(self.tmpdir.join('file_readline_without_eol_at_the_end'))
+        for n in [1, 10, 97, 98, 99, 100, 101, 102, 103, 150]:
+            s = ''.join([chr(32+(k&63)) for k in range(n)])
+            with open(fname, 'wb') as f:
+                f.write(s)
+
+            f = rfile.create_file(fname, 'r')
+            got = f.readline()
+            assert got == s
+            got = f.readline()
+            assert got == ''
+            f.close()
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to