[pypy-commit] pypy file-support-in-rpython: support more of read/write

fijal noreply at buildbot.pypy.org
Wed Sep 18 11:59:01 CEST 2013


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: file-support-in-rpython
Changeset: r66997:ff5bcd269204
Date: 2013-09-18 11:58 +0200
http://bitbucket.org/pypy/pypy/changeset/ff5bcd269204/

Log:	support more of read/write

diff --git a/rpython/rlib/rfile.py b/rpython/rlib/rfile.py
--- a/rpython/rlib/rfile.py
+++ b/rpython/rlib/rfile.py
@@ -2,13 +2,18 @@
 """ This file makes open() and friends RPython
 """
 
-from rpython.annotator.model import SomeObject, SomeString
+from rpython.annotator.model import SomeObject, SomeString, SomeInteger
 from rpython.rtyper.extregistry import ExtRegistryEntry
 
 class SomeFile(SomeObject):
     def method_write(self, s_arg):
         assert isinstance(s_arg, SomeString)
 
+    def method_read(self, s_arg=None):
+        if s_arg is not None:
+            assert isinstance(s_arg, SomeInteger)
+        return SomeString(can_be_None=False)
+
     def method_close(self):
         pass
 
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
@@ -18,3 +18,38 @@
 
         self.interpret(f, [])
         assert open(fname, "r").read() == "dupa"
+
+    def test_read_write(self):
+        fname = str(self.tmpdir.join('file_2'))
+
+        def f():
+            f = open(fname, "w")
+            f.write("dupa")
+            f.close()
+            f2 = open(fname)
+            dupa = f2.read()
+            assert dupa == "dupa"
+            f2.close()
+
+        self.interpret(f, [])
+
+    def test_read_sequentially(self):
+        fname = self.tmpdir.join('file_3')
+        fname.write("dupa")
+        fname = str(fname)
+
+        def f():
+            f = open(fname)
+            a = f.read(1)
+            b = f.read(1)
+            c = f.read(1)
+            d = f.read(1)
+            e = f.read()
+            f.close()
+            assert a == "d"
+            assert b == "u"
+            assert c == "p"
+            assert d == "a"
+            assert e == ""
+
+        self.interpret(f, [])
diff --git a/rpython/rtyper/lltypesystem/rfile.py b/rpython/rtyper/lltypesystem/rfile.py
--- a/rpython/rtyper/lltypesystem/rfile.py
+++ b/rpython/rtyper/lltypesystem/rfile.py
@@ -4,6 +4,7 @@
 from rpython.rlib.rarithmetic import r_uint
 from rpython.annotator import model as annmodel
 from rpython.rtyper.rtyper import Repr
+from rpython.rlib.rstring import StringBuilder
 from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
 from rpython.rtyper.lltypesystem.rstr import string_repr, STR
 from rpython.translator.tool.cbuild import ExternalCompilationInfo
@@ -21,6 +22,11 @@
                           compilation_info=eci)
 c_write = rffi.llexternal('fwrite', [rffi.CCHARP, rffi.SIZE_T, rffi.SIZE_T,
                                      lltype.Ptr(FILE)], rffi.SIZE_T)
+c_read = rffi.llexternal('fread', [rffi.CCHARP, rffi.SIZE_T, rffi.SIZE_T,
+                                   lltype.Ptr(FILE)], rffi.SIZE_T)
+c_feof = rffi.llexternal('feof', [lltype.Ptr(FILE)], rffi.INT)
+c_ferror = rffi.llexternal('ferror', [lltype.Ptr(FILE)], rffi.INT)
+c_clearerror = rffi.llexternal('clearerr', [lltype.Ptr(FILE)], lltype.Void)
 
 def ll_open(name, mode):
     file_wrapper = lltype.malloc(FILE_WRAPPER)
@@ -39,11 +45,14 @@
 
 def ll_write(file_wrapper, value):
     ll_file = file_wrapper.file
+    if not ll_file:
+        raise ValueError("I/O operation on closed file")
     value = hlstr(value)
     assert value is not None
     ll_value = rffi.get_nonmovingbuffer(value)
     try:
-        # NO GC OPERATIONS HERE
+        # note that since we got a nonmoving buffer, it is either raw
+        # or already cannot move, so the arithmetics below are fine
         total_bytes = 0
         ll_current = ll_value
         while total_bytes < len(value):
@@ -59,6 +68,43 @@
     finally:
         rffi.free_nonmovingbuffer(value, ll_value)
 
+BASE_BUF_SIZE = 4096
+
+def ll_read(file_wrapper, size):
+    ll_file = file_wrapper.file
+    if not ll_file:
+        raise ValueError("I/O operation on closed file")
+    if size < 0:
+        # read the entire contents
+        buf = lltype.malloc(rffi.CCHARP.TO, BASE_BUF_SIZE, flavor='raw')
+        try:
+            s = StringBuilder()
+            while True:
+                returned_size = c_read(buf, 1, BASE_BUF_SIZE, ll_file)
+                if returned_size == 0:
+                    if c_feof(ll_file):
+                        # ok, finished
+                        return s.build()
+                    errno = c_ferror(ll_file)
+                    c_clearerror(ll_file)
+                    raise OSError(errno, os.strerror(errno))
+                s.append_charpsize(buf, returned_size)
+        finally:
+            lltype.free(buf, flavor='raw')
+    else:
+        raw_buf, gc_buf = rffi.alloc_buffer(size)
+        try:
+            returned_size = c_read(raw_buf, 1, size, ll_file)
+            if returned_size == 0:
+                if not c_feof(ll_file):
+                    errno = c_ferror(ll_file)
+                    raise OSError(errno, os.strerror(errno))
+            s = rffi.str_from_buffer(raw_buf, gc_buf, size,
+                                     rffi.cast(lltype.Signed, returned_size))
+        finally:
+            rffi.keep_buffer_alive_until_here(raw_buf, gc_buf)
+        return s
+
 def ll_close(file_wrapper):
     if file_wrapper.file:
         # double close is allowed
@@ -77,7 +123,10 @@
     def rtype_constructor(self, hop):
         repr = hop.rtyper.getrepr(annmodel.SomeString())
         arg_0 = hop.inputarg(repr, 0)
-        arg_1 = hop.inputarg(repr, 1)
+        if len(hop.args_v) == 1:
+            arg_1 = hop.inputconst(string_repr, "r")
+        else:
+            arg_1 = hop.inputarg(repr, 1)
         hop.exception_is_here()
         open = hop.rtyper.getannmixlevel().delayedfunction(
             ll_open, [annmodel.SomeString()] * 2,
@@ -95,3 +144,12 @@
         r_self = hop.inputarg(self, 0)
         hop.exception_is_here()
         return hop.gendirectcall(ll_close, r_self)
+
+    def rtype_method_read(self, hop):
+        r_self = hop.inputarg(self, 0)
+        if len(hop.args_v) != 2:
+            arg_1 = hop.inputconst(lltype.Signed, -1)
+        else:
+            arg_1 = hop.inputarg(lltype.Signed, 1)
+        hop.exception_is_here()
+        return hop.gendirectcall(ll_read, r_self, arg_1)


More information about the pypy-commit mailing list