Commits

Armin Rigo committed d23457c

Kill the logic to support FILE. Found out that it seems reasonable
enough to use the standard cffi way.

Comments (0)

Files changed (7)

c/_cffi_backend.c

 #define CT_CUSTOM_FIELD_POS     32768
 #define CT_IS_LONGDOUBLE        65536
 #define CT_IS_BOOL             131072
-#define CT_IS_FILE             262144
 #define CT_PRIMITIVE_ANY  (CT_PRIMITIVE_SIGNED |        \
                            CT_PRIMITIVE_UNSIGNED |      \
                            CT_PRIMITIVE_CHAR |          \
 
 #include "minibuffer.h"
 
-#if PY_MAJOR_VERSION >= 3
-# include "file_emulator.h"
-#endif
-
 #ifdef HAVE_WCHAR_H
 # include "wchar_helper.h"
 #endif
         /* from a unicode, we add the null terminator */
         length = _my_PyUnicode_SizeAsWideChar(init) + 1;
     }
-    else if ((ctitem->ct_flags & CT_IS_FILE) && PyFile_Check(init)) {
-        *output_data = (char *)PyFile_AsFile(init);
-        if (*output_data == NULL && PyErr_Occurred())
-            return -1;
-        return 0;
-    }
     else {
         /* refuse to receive just an integer (and interpret it
            as the array size) */
                 return new_simple_cdata(cdsrc->c_data, ct);
             }
         }
-        if ((ct->ct_flags & CT_POINTER) &&
-                (ct->ct_itemdescr->ct_flags & CT_IS_FILE) &&
-                PyFile_Check(ob)) {
-            FILE *f = PyFile_AsFile(ob);
-            if (f == NULL && PyErr_Occurred())
-                return NULL;
-            return new_simple_cdata((char *)f, ct);
-        }
         value = _my_PyLong_AsUnsignedLongLong(ob, 0);
         if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())
             return NULL;
 static PyObject *b_new_struct_type(PyObject *self, PyObject *args)
 {
     char *name;
-    int flag;
     if (!PyArg_ParseTuple(args, "s:new_struct_type", &name))
         return NULL;
-
-    flag = CT_STRUCT;
-    if (strcmp(name, "_IO_FILE") == 0 || strcmp(name, "$FILE") == 0)
-        flag |= CT_IS_FILE;
-    return _b_struct_or_union_type("struct", name, flag);
+    return _b_struct_or_union_type("struct", name, CT_STRUCT);
 }
 
 static PyObject *b_new_union_type(PyObject *self, PyObject *args)
 static char *_cffi_to_c_pointer(PyObject *obj, CTypeDescrObject *ct)
 {
     char *result;
-    if (convert_from_object((char *)&result, ct, obj) < 0) {
-        if ((ct->ct_flags & CT_POINTER) &&
-                (ct->ct_itemdescr->ct_flags & CT_IS_FILE) &&
-                PyFile_Check(obj)) {
-            PyErr_Clear();
-            return (char *)PyFile_AsFile(obj);
-        }
+    if (convert_from_object((char *)&result, ct, obj) < 0)
         return NULL;
-    }
     return result;
 }
 
     init_errno();
 
 #if PY_MAJOR_VERSION >= 3
-    if (init_file_emulator() < 0)
-        INITERROR;
     return m;
 #endif
 }

c/file_emulator.h

-
-/* Emulation of PyFile_Check() and PyFile_AsFile() for Python 3. */
-
-static PyObject *PyIOBase_TypeObj;
-
-static int init_file_emulator(void)
-{
-    PyObject *io = PyImport_ImportModule("_io");
-    if (io == NULL)
-        return -1;
-    PyIOBase_TypeObj = PyObject_GetAttrString(io, "_IOBase");
-    if (PyIOBase_TypeObj == NULL)
-        return -1;
-    return 0;
-}
-
-
-#define PyFile_Check(p)  PyObject_IsInstance(p, PyIOBase_TypeObj)
-
-
-static void _close_file_capsule(PyObject *ob_capsule)
-{
-    FILE *f = (FILE *)PyCapsule_GetPointer(ob_capsule, "FILE");
-    if (f != NULL)
-        fclose(f);
-}
-
-
-static FILE *PyFile_AsFile(PyObject *ob_file)
-{
-    PyObject *ob, *ob_capsule = NULL, *ob_mode = NULL;
-    FILE *f = NULL;
-    int fd;
-    char *mode;
-
-    ob = PyObject_CallMethod(ob_file, "flush", NULL);
-    if (ob == NULL)
-        goto fail;
-    Py_DECREF(ob);
-
-    ob_capsule = PyObject_GetAttrString(ob_file, "__cffi_FILE");
-    if (ob_capsule == NULL) {
-        PyErr_Clear();
-
-        fd = PyObject_AsFileDescriptor(ob_file);
-        if (fd < 0)
-            goto fail;
-
-        ob_mode = PyObject_GetAttrString(ob_file, "mode");
-        if (ob_mode == NULL)
-            goto fail;
-        mode = PyText_AsUTF8(ob_mode);
-        if (mode == NULL)
-            goto fail;
-
-        fd = dup(fd);
-        if (fd < 0) {
-            PyErr_SetFromErrno(PyExc_OSError);
-            goto fail;
-        }
-
-        f = fdopen(fd, mode);
-        if (f == NULL) {
-            close(fd);
-            PyErr_SetFromErrno(PyExc_OSError);
-            goto fail;
-        }
-        setbuf(f, NULL);    /* non-buffered */
-        Py_DECREF(ob_mode);
-        ob_mode = NULL;
-
-        ob_capsule = PyCapsule_New(f, "FILE", _close_file_capsule);
-        if (ob_capsule == NULL) {
-            fclose(f);
-            goto fail;
-        }
-
-        if (PyObject_SetAttrString(ob_file, "__cffi_FILE", ob_capsule) < 0)
-            goto fail;
-    }
-    return PyCapsule_GetPointer(ob_capsule, "FILE");
-
- fail:
-    Py_XDECREF(ob_mode);
-    Py_XDECREF(ob_capsule);
-    return NULL;
-}
         pass   # win32
 
 def test_FILE():
+    """FILE is not supported natively any more."""
     if sys.platform == "win32":
         py.test.skip("testing FILE not implemented")
     #
     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"
+    py.test.raises(TypeError, fputs, b"hello world\n", fw1)
     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, '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)
-    #
-    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":
         py.test.skip("GetLastError(): only for Windows")

cffi/commontypes.py

 
 
 COMMON_TYPES = {
-    'FILE': model.unknown_type('FILE', '_IO_FILE'),
+    'FILE': model.unknown_type('FILE'),
     'bool': '_Bool',
     }
 
+import cffi
+import os
+
+
+ffi = cffi.FFI()
+
+ffi.cdef("""
+FILE *fdopen(int, const char *);
+int fclose(FILE *);
+void dumpme(FILE *);
+""")
+
+lib = ffi.verify("""
+void dumpme(FILE *f) {
+    char c = 'X';
+    fwrite(&c, 1, 1, f);
+}
+""")
+
+
+
+pipe_in, pipe_out = os.pipe()
+
+file_out = lib.fdopen(pipe_out, "w")
+lib.dumpme(file_out)
+lib.fclose(file_out)
+
+x = os.read(pipe_in, 10)
+assert x == 'X'

testing/test_function.py

         m = ffi.dlopen("m")
         x = m.sin(1.23)
         assert x == math.sin(1.23)
-
-    def test_fputs_custom_FILE(self):
-        if self.Backend is CTypesBackend:
-            py.test.skip("FILE not supported with the ctypes backend")
-        filename = str(udir.join('fputs_custom_FILE'))
-        ffi = FFI(backend=self.Backend())
-        ffi.cdef("int fputs(const char *, FILE *);")
-        C = ffi.dlopen(None)
-        with open(filename, 'wb') as f:
-            f.write(b'[')
-            C.fputs(b"hello from custom file", f)
-            f.write(b'][')
-            C.fputs(b"some more output", f)
-            f.write(b']')
-        with open(filename, 'rb') as f:
-            res = f.read()
-        assert res == b'[hello from custom file][some more output]'

testing/test_verify.py

     if sys.platform == 'win32':
         py.test.skip("MSVC: cannot assign to stdout")
     ffi = FFI()
-    ffi.cdef("int printf(const char *, ...); FILE *setstdout(FILE *);")
+    ffi.cdef("""
+        FILE *fdopen(int, const char *);
+        int fclose(FILE *);
+        size_t fwrite(const void *ptr, size_t size, size_t nmemb,
+                      FILE *stream);
+        int printf(const char *, ...);
+        FILE *setstdout(FILE *);
+    """)
     lib = ffi.verify("""
         #include <stdio.h>
         FILE *setstdout(FILE *f) {
     """)
     import os
     fdr, fdw = os.pipe()
-    fw1 = os.fdopen(fdw, 'wb', 256)
+    fw1 = lib.fdopen(fdw, 'wb')
     old_stdout = lib.setstdout(fw1)
     try:
         #
-        fw1.write(b"X")
+        lib.fwrite(b"X", 1, 1, fw1)
         r = lib.printf(b"hello, %d!\n", ffi.cast("int", 42))
-        fw1.close()
+        lib.fclose(fw1)
         assert r == len("hello, 42!\n")
         #
     finally:
     #
     result = os.read(fdr, 256)
     os.close(fdr)
-    # the 'X' might remain in the user-level buffer of 'fw1' and
-    # end up showing up after the 'hello, 42!\n'
-    assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX"
-
-def test_FILE_stored_explicitly():
-    ffi = FFI()
-    ffi.cdef("int myprintf(const char *, int); FILE *myfile;")
-    lib = ffi.verify("""
-        #include <stdio.h>
-        FILE *myfile;
-        int myprintf(const char *out, int value) {
-            return fprintf(myfile, out, value);
-        }
-    """)
-    import os
-    fdr, fdw = os.pipe()
-    fw1 = os.fdopen(fdw, 'wb', 256)
-    lib.myfile = ffi.cast("FILE *", fw1)
-    #
-    fw1.write(b"X")
-    r = lib.myprintf(b"hello, %d!\n", ffi.cast("int", 42))
-    fw1.close()
-    assert r == len("hello, 42!\n")
-    #
-    result = os.read(fdr, 256)
-    os.close(fdr)
-    # the 'X' might remain in the user-level buffer of 'fw1' and
-    # end up showing up after the 'hello, 42!\n'
-    assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX"
+    assert result == b"Xhello, 42!\n"
 
 def test_global_array_with_missing_length():
     ffi = FFI()