diff options
Diffstat (limited to 'c/file_emulator.h')
-rw-r--r-- | c/file_emulator.h | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/c/file_emulator.h b/c/file_emulator.h new file mode 100644 index 0000000..82a34c0 --- /dev/null +++ b/c/file_emulator.h @@ -0,0 +1,93 @@ + +/* Emulation of PyFile_Check() and PyFile_AsFile() for Python 3. */ + +static PyObject *PyIOBase_TypeObj; + +static int init_file_emulator(void) +{ + if (PyIOBase_TypeObj == NULL) { + 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; + int fd; + const 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; + } + else { + f = PyCapsule_GetPointer(ob_capsule, "FILE"); + } + Py_DECREF(ob_capsule); /* assumes still at least one reference */ + return f; + + fail: + Py_XDECREF(ob_mode); + Py_XDECREF(ob_capsule); + return NULL; +} |