[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