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

Log:    Implement RFile.readline(), step 1

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 = 1000
 
 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,35 @@
     def __del__(self):
         self.close()
 
+    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))
+                #
+                # 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 or
+                      raw_buf[BASE_LINE_SIZE - 2] == '\n'):
+                    # common case
+                    return rffi.str_from_buffer(raw_buf, gc_buf,
+                                                BASE_LINE_SIZE, strlen)
+                #
+                XXX
+
+            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,27 @@
 
         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(50):
+                s = ''.join([chr(32+(k&63)) for k in range(j, j + i*7)])
+                print >> f, s
+            f.write('no newline')
+        expected = open(fname).readlines()
+
+        f = rfile.create_file(fname, 'r')
+        got = []
+        for j in range(53):
+            got.append(f.readline())
+        f.close()
+        assert got == expected + ['', '']
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to