Author: Maciej Fijalkowski <[email protected]>
Branch: fileops2
Changeset: r67215:70dcd6a26b2c
Date: 2013-10-08 16:56 +0200
http://bitbucket.org/pypy/pypy/changeset/70dcd6a26b2c/

Log:    merge

diff --git a/rpython/rlib/rfile.py b/rpython/rlib/rfile.py
--- a/rpython/rlib/rfile.py
+++ b/rpython/rlib/rfile.py
@@ -43,8 +43,11 @@
 c_ftell = llexternal('ftell', [lltype.Ptr(FILE)], lltype.Signed)
 c_fflush = llexternal('fflush', [lltype.Ptr(FILE)], rffi.INT)
 c_ftruncate = llexternal('ftruncate', [rffi.INT, OFF_T], rffi.INT)
+c_fgets = llexternal('fgets', [rffi.CCHARP, rffi.INT, lltype.Ptr(FILE)],
+                     rffi.CCHARP)
 
 BASE_BUF_SIZE = 4096
+BASE_LINE_SIZE = 100
 
 def create_file(filename, mode="r", buffering=-1):
     assert buffering == -1
@@ -110,6 +113,7 @@
                 raise OSError(errno, os.strerror(errno))
 
     def read(self, size=-1):
+        # XXX CPython uses a more delicate logic here
         ll_file = self.ll_file
         if not ll_file:
             raise ValueError("I/O operation on closed file")
@@ -190,3 +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:
+                c = self._readline1(raw_buf)
+                if c >= 0:
+                    return rffi.str_from_buffer(raw_buf, gc_buf,
+                                                BASE_LINE_SIZE, c)
+                #
+                # 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
+                #
+                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
@@ -135,3 +135,42 @@
 
         f()
         self.interpret(f, [])
+
+
+class TestDirect:
+    def setup_class(cls):
+        cls.tmpdir = udir.join('test_rfile_direct')
+        cls.tmpdir.ensure(dir=True)
+
+    def test_readline(self):
+        fname = str(self.tmpdir.join('file_readline'))
+        j = 0
+        expected = []
+        with open(fname, 'w') as f:
+            for i in range(150):
+                s = ''.join([chr(32+(k&63)) for k in range(j, j + i)])
+                j += 1
+                print >> f, s
+        expected = open(fname).readlines()
+        expected += ['', '']
+        assert len(expected) == 152
+
+        f = rfile.create_file(fname, 'r')
+        for j in range(152):
+            got = f.readline()
+            assert got == expected[j]
+        f.close()
+
+    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