Author: Maciej Fijalkowski <fij...@gmail.com> Branch: Changeset: r58483:0fe28351555a Date: 2012-10-26 23:04 +0200 http://bitbucket.org/pypy/pypy/changeset/0fe28351555a/
Log: merge diff --git a/pypy/module/_cffi_backend/ctypefunc.py b/pypy/module/_cffi_backend/ctypefunc.py --- a/pypy/module/_cffi_backend/ctypefunc.py +++ b/pypy/module/_cffi_backend/ctypefunc.py @@ -4,9 +4,8 @@ import sys from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.error import wrap_oserror from pypy.rpython.lltypesystem import lltype, llmemory, rffi -from pypy.rlib import jit, clibffi, jit_libffi, rposix +from pypy.rlib import jit, clibffi, jit_libffi from pypy.rlib.jit_libffi import CIF_DESCRIPTION, CIF_DESCRIPTION_P from pypy.rlib.jit_libffi import FFI_TYPE, FFI_TYPE_P, FFI_TYPE_PP from pypy.rlib.jit_libffi import SIZE_OF_FFI_ARG @@ -152,9 +151,6 @@ if flag == 1: raw_string = rffi.cast(rffi.CCHARPP, data)[0] lltype.free(raw_string, flavor='raw') - elif flag == 2: - file = rffi.cast(rffi.CCHARPP, data)[0] - rffi_fclose(file) lltype.free(buffer, flavor='raw') return w_res @@ -169,27 +165,6 @@ assert isinstance(abi, int) return space.wrap(abi) -rffi_fdopen = rffi.llexternal("fdopen", [rffi.INT, rffi.CCHARP], rffi.CCHARP) -rffi_fclose = rffi.llexternal("fclose", [rffi.CCHARP], rffi.INT) - -def prepare_file_call_argument(fileobj): - import os - space = fileobj.space - fileobj.direct_flush() - fd = fileobj.direct_fileno() - if fd < 0: - raise OperationError(space.w_ValueError, - space.wrap("file has no OS file descriptor")) - try: - fd2 = os.dup(fd) - f = rffi_fdopen(fd2, fileobj.mode) - if not f: - os.close(fd2) - raise OSError(rposix.get_errno(), "fdopen failed") - except OSError, e: - raise wrap_oserror(space, e) - return f - # ____________________________________________________________ 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 @@ -3,9 +3,11 @@ """ from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import wrap_oserror from pypy.rpython.lltypesystem import lltype, rffi from pypy.rlib.objectmodel import keepalive_until_here from pypy.rlib.rarithmetic import ovfcheck +from pypy.rlib import rposix from pypy.module._cffi_backend.ctypeobj import W_CType from pypy.module._cffi_backend import cdataobj, misc, ctypeprim @@ -236,6 +238,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,11 +263,8 @@ # from a string, we add the null terminator length = space.int_w(space.len(w_init)) + 1 elif self.is_file: - from pypy.module._file.interp_file import W_File - from pypy.module._cffi_backend import ctypefunc - ob = space.interpclass_w(w_init) - if isinstance(ob, W_File): - result = ctypefunc.prepare_file_call_argument(ob) + result = self.prepare_file(w_init) + if result: rffi.cast(rffi.CCHARPP, cdata)[0] = result return 2 return 0 @@ -303,3 +318,31 @@ else: raise OperationError(space.w_TypeError, space.wrap("expected a 'cdata struct-or-union' object")) + +# ____________________________________________________________ + + +rffi_fdopen = rffi.llexternal("fdopen", [rffi.INT, rffi.CCHARP], rffi.CCHARP) +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") + 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 @@ -2264,3 +2264,35 @@ e = py.test.raises(TypeError, fputs, b"hello world\n", fw1) assert str(e.value) == ("initializer for ctype 'struct NOT_FILE *' must " "be a cdata pointer, not file") + +def test_FILE_object(): + if sys.platform == "win32": + py.test.skip("testing FILE not implemented") + # + BFILE = new_struct_type("_IO_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) + # + 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 + fw1.close() + # + data = posix.read(fdr, 256) + assert data == b"Xhello\n" + posix.close(fdr) 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 pypy.rpython.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,7 +149,14 @@ del openstreams[stream] except KeyError: pass - stream.close() + # 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 diff --git a/pypy/rlib/streamio.py b/pypy/rlib/streamio.py --- a/pypy/rlib/streamio.py +++ b/pypy/rlib/streamio.py @@ -268,6 +268,9 @@ return False def close(self): + self.close1(True) + + def close1(self, closefileno): pass def peek(self): @@ -333,8 +336,9 @@ else: data = data[n:] - def close(self): - os.close(self.fd) + def close1(self, closefileno): + if closefileno: + os.close(self.fd) if sys.platform == "win32": def truncate(self, size): @@ -375,9 +379,10 @@ size = os.fstat(self.fd).st_size self.mm = mmap.mmap(self.fd, size, access=self.access) - def close(self): + def close1(self, closefileno): self.mm.close() - os.close(self.fd) + if closefileno: + os.close(self.fd) def tell(self): return self.pos @@ -470,7 +475,7 @@ ("truncate", [r_longlong]), ("flush", []), ("flushable", []), - ("close", []), + ("close1", [int]), ("peek", []), ("try_to_find_file_descriptor", []), ("getnewlines", []), @@ -715,7 +720,7 @@ truncate = PassThrough("truncate", flush_buffers=True) flush = PassThrough("flush", flush_buffers=True) flushable = PassThrough("flushable", flush_buffers=False) - close = PassThrough("close", flush_buffers=False) + close1 = PassThrough("close1", flush_buffers=False) try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor", flush_buffers=False) @@ -770,7 +775,7 @@ seek = PassThrough("seek", flush_buffers=True) truncate = PassThrough("truncate", flush_buffers=True) flush = PassThrough("flush", flush_buffers=True) - close = PassThrough("close", flush_buffers=True) + close1 = PassThrough("close1", flush_buffers=True) try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor", flush_buffers=False) @@ -838,7 +843,7 @@ flush = PassThrough("flush", flush_buffers=False) flushable= PassThrough("flushable", flush_buffers=False) - close = PassThrough("close", flush_buffers=False) + close1 = PassThrough("close1", flush_buffers=False) try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor", flush_buffers=False) @@ -907,7 +912,7 @@ truncate = PassThrough("truncate", flush_buffers=True) flush = PassThrough("flush", flush_buffers=False) flushable= PassThrough("flushable", flush_buffers=False) - close = PassThrough("close", flush_buffers=False) + close1 = PassThrough("close1", flush_buffers=False) try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor", flush_buffers=False) @@ -1041,7 +1046,7 @@ truncate = PassThrough("truncate", flush_buffers=True) flush = PassThrough("flush", flush_buffers=True) flushable = PassThrough("flushable", flush_buffers=False) - close = PassThrough("close", flush_buffers=False) + close1 = PassThrough("close1", flush_buffers=False) try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor", flush_buffers=False) @@ -1067,7 +1072,7 @@ truncate = PassThrough("truncate", flush_buffers=False) flush = PassThrough("flush", flush_buffers=False) flushable = PassThrough("flushable", flush_buffers=False) - close = PassThrough("close", flush_buffers=False) + close1 = PassThrough("close1", flush_buffers=False) try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor", flush_buffers=False) @@ -1091,7 +1096,7 @@ peek = PassThrough("peek", flush_buffers=False) flush = PassThrough("flush", flush_buffers=False) flushable = PassThrough("flushable", flush_buffers=False) - close = PassThrough("close", flush_buffers=False) + close1 = PassThrough("close1", flush_buffers=False) write = PassThrough("write", flush_buffers=False) truncate = PassThrough("truncate", flush_buffers=False) getnewlines= PassThrough("getnewlines",flush_buffers=False) @@ -1144,7 +1149,7 @@ truncate = PassThrough("truncate", flush_buffers=False) flush = PassThrough("flush", flush_buffers=False) flushable = PassThrough("flushable", flush_buffers=False) - close = PassThrough("close", flush_buffers=False) + close1 = PassThrough("close1", flush_buffers=False) try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor", flush_buffers=False) @@ -1172,6 +1177,6 @@ truncate = PassThrough("truncate", flush_buffers=False) flush = PassThrough("flush", flush_buffers=False) flushable = PassThrough("flushable", flush_buffers=False) - close = PassThrough("close", flush_buffers=False) + close1 = PassThrough("close1", flush_buffers=False) try_to_find_file_descriptor = PassThrough("try_to_find_file_descriptor", flush_buffers=False) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit