Author: Armin Rigo <[email protected]>
Branch:
Changeset: r62232:0330fbbfcb0b
Date: 2013-03-08 15:20 +0100
http://bitbucket.org/pypy/pypy/changeset/0330fbbfcb0b/
Log: hg backout 87cc13e1bc5e
diff --git a/pypy/module/_cffi_backend/ctypeptr.py
b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -174,8 +174,8 @@
class W_CTypePointer(W_CTypePtrBase):
- _attrs_ = ['cache_array_type']
- _immutable_fields_ = ['cache_array_type?']
+ _attrs_ = ['is_file', 'cache_array_type']
+ _immutable_fields_ = ['is_file', 'cache_array_type?']
kind = "pointer"
cache_array_type = None
@@ -186,6 +186,8 @@
extra = "(*)" # obscure case: see test_array_add
else:
extra = " *"
+ self.is_file = (ctitem.name == "struct _IO_FILE" or
+ ctitem.name == "struct $FILE")
W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem)
def newp(self, w_init):
@@ -237,6 +239,22 @@
p = rffi.ptradd(cdata, i * self.ctitem.size)
return cdataobj.W_CData(space, p, self)
+ def cast(self, w_ob):
+ if self.is_file:
+ value = self.prepare_file(w_ob)
+ if value:
+ return cdataobj.W_CData(self.space, value, self)
+ return W_CTypePtrBase.cast(self, w_ob)
+
+ def prepare_file(self, w_ob):
+ from pypy.module._file.interp_file import W_File
+ from pypy.module._cffi_backend import ctypefunc
+ ob = self.space.interpclass_w(w_ob)
+ if isinstance(ob, W_File):
+ return prepare_file_argument(self.space, ob)
+ else:
+ return lltype.nullptr(rffi.CCHARP.TO)
+
def _prepare_pointer_call_argument(self, w_init, cdata):
space = self.space
if (space.isinstance_w(w_init, space.w_list) or
@@ -245,14 +263,20 @@
elif space.isinstance_w(w_init, space.w_basestring):
# from a string, we add the null terminator
length = space.int_w(space.len(w_init)) + 1
+ elif self.is_file:
+ result = self.prepare_file(w_init)
+ if result:
+ rffi.cast(rffi.CCHARPP, cdata)[0] = result
+ return 2
+ return 0
else:
- return False
+ return 0
itemsize = self.ctitem.size
if itemsize <= 0:
if isinstance(self.ctitem, ctypevoid.W_CTypeVoid):
itemsize = 1
else:
- return False
+ return 0
try:
datasize = ovfcheck(length * itemsize)
except OverflowError:
@@ -266,7 +290,7 @@
lltype.free(result, flavor='raw')
raise
rffi.cast(rffi.CCHARPP, cdata)[0] = result
- return True
+ return 1
def convert_argument_from_object(self, cdata, w_ob):
from pypy.module._cffi_backend.ctypefunc import set_mustfree_flag
@@ -274,7 +298,7 @@
ob = space.interpclass_w(w_ob)
result = (not isinstance(ob, cdataobj.W_CData) and
self._prepare_pointer_call_argument(w_ob, cdata))
- if not result:
+ if result == 0:
self.convert_from_object(cdata, w_ob)
set_mustfree_flag(cdata, result)
return result
@@ -304,3 +328,36 @@
if attrchar == 'i': # item
return self.space.wrap(self.ctitem)
return W_CTypePtrBase._fget(self, attrchar)
+
+# ____________________________________________________________
+
+
+rffi_fdopen = rffi.llexternal("fdopen", [rffi.INT, rffi.CCHARP], rffi.CCHARP)
+rffi_setbuf = rffi.llexternal("setbuf", [rffi.CCHARP, rffi.CCHARP],
lltype.Void)
+rffi_fclose = rffi.llexternal("fclose", [rffi.CCHARP], rffi.INT)
+
+class CffiFileObj(object):
+ _immutable_ = True
+
+ def __init__(self, fd, mode):
+ self.llf = rffi_fdopen(fd, mode)
+ if not self.llf:
+ raise OSError(rposix.get_errno(), "fdopen failed")
+ rffi_setbuf(self.llf, lltype.nullptr(rffi.CCHARP.TO))
+
+ def close(self):
+ rffi_fclose(self.llf)
+
+
+def prepare_file_argument(space, fileobj):
+ fileobj.direct_flush()
+ if fileobj.cffi_fileobj is None:
+ fd = fileobj.direct_fileno()
+ if fd < 0:
+ raise OperationError(space.w_ValueError,
+ space.wrap("file has no OS file descriptor"))
+ try:
+ fileobj.cffi_fileobj = CffiFileObj(fd, fileobj.mode)
+ except OSError, e:
+ raise wrap_oserror(space, e)
+ return fileobj.cffi_fileobj.llf
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py
b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -2497,7 +2497,6 @@
pass # win32
def test_FILE():
- """FILE is not supported natively any more."""
if sys.platform == "win32":
py.test.skip("testing FILE not implemented")
#
@@ -2507,16 +2506,82 @@
BCharP = new_pointer_type(BChar)
BInt = new_primitive_type("int")
BFunc = new_function_type((BCharP, BFILEP), BInt, False)
+ BFunc2 = new_function_type((BFILEP, BCharP), BInt, True)
+ ll = find_and_load_library('c')
+ fputs = ll.load_function(BFunc, "fputs")
+ fscanf = ll.load_function(BFunc2, "fscanf")
+ #
+ import posix
+ fdr, fdw = posix.pipe()
+ fr1 = posix.fdopen(fdr, 'rb', 256)
+ fw1 = posix.fdopen(fdw, 'wb', 256)
+ #
+ fw1.write(b"X")
+ res = fputs(b"hello world\n", fw1)
+ assert res >= 0
+ fw1.flush() # should not be needed
+ #
+ p = newp(new_array_type(BCharP, 100), None)
+ res = fscanf(fr1, b"%s\n", p)
+ assert res == 1
+ assert string(p) == b"Xhello"
+ fr1.close()
+ fw1.close()
+
+def test_FILE_only_for_FILE_arg():
+ if sys.platform == "win32":
+ py.test.skip("testing FILE not implemented")
+ #
+ B_NOT_FILE = new_struct_type("NOT_FILE")
+ B_NOT_FILEP = new_pointer_type(B_NOT_FILE)
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BInt = new_primitive_type("int")
+ BFunc = new_function_type((BCharP, B_NOT_FILEP), BInt, False)
ll = find_and_load_library('c')
fputs = ll.load_function(BFunc, "fputs")
#
import posix
fdr, fdw = posix.pipe()
- fr1 = posix.fdopen(fdr, 'rb', 256)
+ fr1 = posix.fdopen(fdr, 'r')
+ fw1 = posix.fdopen(fdw, 'w')
+ #
+ e = py.test.raises(TypeError, fputs, b"hello world\n", fw1)
+ assert str(e.value).startswith(
+ "initializer for ctype 'struct NOT_FILE *' must "
+ "be a cdata pointer, not ")
+
+def test_FILE_object():
+ if sys.platform == "win32":
+ py.test.skip("testing FILE not implemented")
+ #
+ BFILE = new_struct_type("$FILE")
+ BFILEP = new_pointer_type(BFILE)
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BInt = new_primitive_type("int")
+ BFunc = new_function_type((BCharP, BFILEP), BInt, False)
+ BFunc2 = new_function_type((BFILEP,), BInt, False)
+ ll = find_and_load_library('c')
+ fputs = ll.load_function(BFunc, "fputs")
+ fileno = ll.load_function(BFunc2, "fileno")
+ #
+ import posix
+ fdr, fdw = posix.pipe()
fw1 = posix.fdopen(fdw, 'wb', 256)
- py.test.raises(TypeError, fputs, b"hello world\n", fw1)
- fr1.close()
+ #
+ fw1p = cast(BFILEP, fw1)
+ fw1.write(b"X")
+ fw1.flush()
+ res = fputs(b"hello\n", fw1p)
+ assert res >= 0
+ res = fileno(fw1p)
+ assert (res == fdw) == (sys.version_info < (3,))
fw1.close()
+ #
+ data = posix.read(fdr, 256)
+ assert data == b"Xhello\n"
+ posix.close(fdr)
def test_GetLastError():
if sys.platform != "win32":
diff --git a/pypy/module/_cffi_backend/test/test_ztranslation.py
b/pypy/module/_cffi_backend/test/test_ztranslation.py
--- a/pypy/module/_cffi_backend/test/test_ztranslation.py
+++ b/pypy/module/_cffi_backend/test/test_ztranslation.py
@@ -1,8 +1,21 @@
from pypy.objspace.fake.checkmodule import checkmodule
+from pypy.module._cffi_backend import ctypeptr
+from rpython.rtyper.lltypesystem import lltype, rffi
# side-effect: FORMAT_LONGDOUBLE must be built before test_checkmodule()
from pypy.module._cffi_backend import misc
def test_checkmodule():
- checkmodule('_cffi_backend')
+ # prepare_file_argument() is not working without translating the _file
+ # module too
+ def dummy_prepare_file_argument(space, fileobj):
+ return lltype.nullptr(rffi.CCHARP.TO)
+ old = ctypeptr.prepare_file_argument
+ try:
+ ctypeptr.prepare_file_argument = dummy_prepare_file_argument
+ #
+ checkmodule('_cffi_backend')
+ #
+ finally:
+ ctypeptr.prepare_file_argument = old
diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py
--- a/pypy/module/_file/interp_file.py
+++ b/pypy/module/_file/interp_file.py
@@ -32,6 +32,7 @@
encoding = None
errors = None
fd = -1
+ cffi_fileobj = None # pypy/module/_cffi_backend
newlines = 0 # Updated when the stream is closed
@@ -148,8 +149,14 @@
del openstreams[stream]
except KeyError:
pass
- # close the stream.
- stream.close1(True)
+ # close the stream. If cffi_fileobj is None, we close the
+ # underlying fileno too. Otherwise, we leave that to
+ # cffi_fileobj.close().
+ cffifo = self.cffi_fileobj
+ self.cffi_fileobj = None
+ stream.close1(cffifo is None)
+ if cffifo is not None:
+ cffifo.close()
def direct_fileno(self):
self.getstream() # check if the file is still open
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit