Kaydet (Commit) f7ec1fd8 authored tarafından Antoine Pitrou's avatar Antoine Pitrou

Merged revisions 80798 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/branches/py3k

................
  r80798 | antoine.pitrou | 2010-05-05 18:31:07 +0200 (mer., 05 mai 2010) | 9 lines

  Merged revisions 80796 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r80796 | antoine.pitrou | 2010-05-05 18:27:30 +0200 (mer., 05 mai 2010) | 3 lines

    Untabify Modules/_io/fileio.c
  ........
................
üst 30dc1a73
...@@ -43,14 +43,14 @@ ...@@ -43,14 +43,14 @@
#endif #endif
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
int fd; int fd;
unsigned int readable : 1; unsigned int readable : 1;
unsigned int writable : 1; unsigned int writable : 1;
signed int seekable : 2; /* -1 means unknown */ signed int seekable : 2; /* -1 means unknown */
unsigned int closefd : 1; unsigned int closefd : 1;
PyObject *weakreflist; PyObject *weakreflist;
PyObject *dict; PyObject *dict;
} fileio; } fileio;
PyTypeObject PyFileIO_Type; PyTypeObject PyFileIO_Type;
...@@ -60,7 +60,7 @@ PyTypeObject PyFileIO_Type; ...@@ -60,7 +60,7 @@ PyTypeObject PyFileIO_Type;
int int
_PyFileIO_closed(PyObject *self) _PyFileIO_closed(PyObject *self)
{ {
return ((fileio *)self)->fd < 0; return ((fileio *)self)->fd < 0;
} }
static PyObject * static PyObject *
...@@ -72,64 +72,64 @@ static PyObject *portable_lseek(int fd, PyObject *posobj, int whence); ...@@ -72,64 +72,64 @@ static PyObject *portable_lseek(int fd, PyObject *posobj, int whence);
static int static int
internal_close(fileio *self) internal_close(fileio *self)
{ {
int err = 0; int err = 0;
int save_errno = 0; int save_errno = 0;
if (self->fd >= 0) { if (self->fd >= 0) {
int fd = self->fd; int fd = self->fd;
self->fd = -1; self->fd = -1;
/* fd is accessible and someone else may have closed it */ /* fd is accessible and someone else may have closed it */
if (_PyVerify_fd(fd)) { if (_PyVerify_fd(fd)) {
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
err = close(fd); err = close(fd);
if (err < 0) if (err < 0)
save_errno = errno; save_errno = errno;
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
} else { } else {
save_errno = errno; save_errno = errno;
err = -1; err = -1;
} }
} }
if (err < 0) { if (err < 0) {
errno = save_errno; errno = save_errno;
PyErr_SetFromErrno(PyExc_IOError); PyErr_SetFromErrno(PyExc_IOError);
return -1; return -1;
} }
return 0; return 0;
} }
static PyObject * static PyObject *
fileio_close(fileio *self) fileio_close(fileio *self)
{ {
if (!self->closefd) { if (!self->closefd) {
self->fd = -1; self->fd = -1;
Py_RETURN_NONE; Py_RETURN_NONE;
} }
errno = internal_close(self); errno = internal_close(self);
if (errno < 0) if (errno < 0)
return NULL; return NULL;
return PyObject_CallMethod((PyObject*)&PyRawIOBase_Type, return PyObject_CallMethod((PyObject*)&PyRawIOBase_Type,
"close", "O", self); "close", "O", self);
} }
static PyObject * static PyObject *
fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{ {
fileio *self; fileio *self;
assert(type != NULL && type->tp_alloc != NULL); assert(type != NULL && type->tp_alloc != NULL);
self = (fileio *) type->tp_alloc(type, 0); self = (fileio *) type->tp_alloc(type, 0);
if (self != NULL) { if (self != NULL) {
self->fd = -1; self->fd = -1;
self->readable = 0; self->readable = 0;
self->writable = 0; self->writable = 0;
self->seekable = -1; self->seekable = -1;
self->closefd = 1; self->closefd = 1;
self->weakreflist = NULL; self->weakreflist = NULL;
} }
return (PyObject *) self; return (PyObject *) self;
} }
/* On Unix, open will succeed for directories. /* On Unix, open will succeed for directories.
...@@ -140,538 +140,538 @@ static int ...@@ -140,538 +140,538 @@ static int
dircheck(fileio* self, const char *name) dircheck(fileio* self, const char *name)
{ {
#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR) #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
struct stat buf; struct stat buf;
if (self->fd < 0) if (self->fd < 0)
return 0; return 0;
if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) { if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) {
char *msg = strerror(EISDIR); char *msg = strerror(EISDIR);
PyObject *exc; PyObject *exc;
if (internal_close(self)) if (internal_close(self))
return -1; return -1;
exc = PyObject_CallFunction(PyExc_IOError, "(iss)", exc = PyObject_CallFunction(PyExc_IOError, "(iss)",
EISDIR, msg, name); EISDIR, msg, name);
PyErr_SetObject(PyExc_IOError, exc); PyErr_SetObject(PyExc_IOError, exc);
Py_XDECREF(exc); Py_XDECREF(exc);
return -1; return -1;
} }
#endif #endif
return 0; return 0;
} }
static int static int
check_fd(int fd) check_fd(int fd)
{ {
#if defined(HAVE_FSTAT) #if defined(HAVE_FSTAT)
struct stat buf; struct stat buf;
if (!_PyVerify_fd(fd) || (fstat(fd, &buf) < 0 && errno == EBADF)) { if (!_PyVerify_fd(fd) || (fstat(fd, &buf) < 0 && errno == EBADF)) {
PyObject *exc; PyObject *exc;
char *msg = strerror(EBADF); char *msg = strerror(EBADF);
exc = PyObject_CallFunction(PyExc_OSError, "(is)", exc = PyObject_CallFunction(PyExc_OSError, "(is)",
EBADF, msg); EBADF, msg);
PyErr_SetObject(PyExc_OSError, exc); PyErr_SetObject(PyExc_OSError, exc);
Py_XDECREF(exc); Py_XDECREF(exc);
return -1; return -1;
} }
#endif #endif
return 0; return 0;
} }
static int static int
fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
{ {
fileio *self = (fileio *) oself; fileio *self = (fileio *) oself;
static char *kwlist[] = {"file", "mode", "closefd", NULL}; static char *kwlist[] = {"file", "mode", "closefd", NULL};
const char *name = NULL; const char *name = NULL;
PyObject *nameobj, *stringobj = NULL; PyObject *nameobj, *stringobj = NULL;
char *mode = "r"; char *mode = "r";
char *s; char *s;
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
Py_UNICODE *widename = NULL; Py_UNICODE *widename = NULL;
#endif #endif
int ret = 0; int ret = 0;
int rwa = 0, plus = 0, append = 0; int rwa = 0, plus = 0, append = 0;
int flags = 0; int flags = 0;
int fd = -1; int fd = -1;
int closefd = 1; int closefd = 1;
assert(PyFileIO_Check(oself)); assert(PyFileIO_Check(oself));
if (self->fd >= 0) { if (self->fd >= 0) {
/* Have to close the existing file first. */ /* Have to close the existing file first. */
if (internal_close(self) < 0) if (internal_close(self) < 0)
return -1; return -1;
} }
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|si:fileio", if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|si:fileio",
kwlist, &nameobj, &mode, &closefd)) kwlist, &nameobj, &mode, &closefd))
return -1; return -1;
if (PyFloat_Check(nameobj)) { if (PyFloat_Check(nameobj)) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"integer argument expected, got float"); "integer argument expected, got float");
return -1; return -1;
} }
fd = PyLong_AsLong(nameobj); fd = PyLong_AsLong(nameobj);
if (fd < 0) { if (fd < 0) {
if (!PyErr_Occurred()) { if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"Negative filedescriptor"); "Negative filedescriptor");
return -1; return -1;
} }
PyErr_Clear(); PyErr_Clear();
} }
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
if (GetVersion() < 0x80000000) { if (GetVersion() < 0x80000000) {
/* On NT, so wide API available */ /* On NT, so wide API available */
if (PyUnicode_Check(nameobj)) if (PyUnicode_Check(nameobj))
widename = PyUnicode_AS_UNICODE(nameobj); widename = PyUnicode_AS_UNICODE(nameobj);
} }
if (widename == NULL) if (widename == NULL)
#endif #endif
if (fd < 0) if (fd < 0)
{ {
if (PyBytes_Check(nameobj) || PyByteArray_Check(nameobj)) { if (PyBytes_Check(nameobj) || PyByteArray_Check(nameobj)) {
Py_ssize_t namelen; Py_ssize_t namelen;
if (PyObject_AsCharBuffer(nameobj, &name, &namelen) < 0) if (PyObject_AsCharBuffer(nameobj, &name, &namelen) < 0)
return -1; return -1;
} }
else { else {
PyObject *u = PyUnicode_FromObject(nameobj); PyObject *u = PyUnicode_FromObject(nameobj);
if (u == NULL) if (u == NULL)
return -1; return -1;
stringobj = PyUnicode_AsEncodedString( stringobj = PyUnicode_AsEncodedString(
u, Py_FileSystemDefaultEncoding, "surrogateescape"); u, Py_FileSystemDefaultEncoding, "surrogateescape");
Py_DECREF(u); Py_DECREF(u);
if (stringobj == NULL) if (stringobj == NULL)
return -1; return -1;
if (!PyBytes_Check(stringobj)) { if (!PyBytes_Check(stringobj)) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"encoder failed to return bytes"); "encoder failed to return bytes");
goto error; goto error;
} }
name = PyBytes_AS_STRING(stringobj); name = PyBytes_AS_STRING(stringobj);
} }
} }
s = mode; s = mode;
while (*s) { while (*s) {
switch (*s++) { switch (*s++) {
case 'r': case 'r':
if (rwa) { if (rwa) {
bad_mode: bad_mode:
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"Must have exactly one of read/write/append mode"); "Must have exactly one of read/write/append mode");
goto error; goto error;
} }
rwa = 1; rwa = 1;
self->readable = 1; self->readable = 1;
break; break;
case 'w': case 'w':
if (rwa) if (rwa)
goto bad_mode; goto bad_mode;
rwa = 1; rwa = 1;
self->writable = 1; self->writable = 1;
flags |= O_CREAT | O_TRUNC; flags |= O_CREAT | O_TRUNC;
break; break;
case 'a': case 'a':
if (rwa) if (rwa)
goto bad_mode; goto bad_mode;
rwa = 1; rwa = 1;
self->writable = 1; self->writable = 1;
flags |= O_CREAT; flags |= O_CREAT;
append = 1; append = 1;
break; break;
case 'b': case 'b':
break; break;
case '+': case '+':
if (plus) if (plus)
goto bad_mode; goto bad_mode;
self->readable = self->writable = 1; self->readable = self->writable = 1;
plus = 1; plus = 1;
break; break;
default: default:
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
"invalid mode: %.200s", mode); "invalid mode: %.200s", mode);
goto error; goto error;
} }
} }
if (!rwa) if (!rwa)
goto bad_mode; goto bad_mode;
if (self->readable && self->writable) if (self->readable && self->writable)
flags |= O_RDWR; flags |= O_RDWR;
else if (self->readable) else if (self->readable)
flags |= O_RDONLY; flags |= O_RDONLY;
else else
flags |= O_WRONLY; flags |= O_WRONLY;
#ifdef O_BINARY #ifdef O_BINARY
flags |= O_BINARY; flags |= O_BINARY;
#endif #endif
#ifdef O_APPEND #ifdef O_APPEND
if (append) if (append)
flags |= O_APPEND; flags |= O_APPEND;
#endif #endif
if (fd >= 0) { if (fd >= 0) {
if (check_fd(fd)) if (check_fd(fd))
goto error; goto error;
self->fd = fd; self->fd = fd;
self->closefd = closefd; self->closefd = closefd;
} }
else { else {
self->closefd = 1; self->closefd = 1;
if (!closefd) { if (!closefd) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"Cannot use closefd=False with file name"); "Cannot use closefd=False with file name");
goto error; goto error;
} }
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
errno = 0; errno = 0;
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
if (widename != NULL) if (widename != NULL)
self->fd = _wopen(widename, flags, 0666); self->fd = _wopen(widename, flags, 0666);
else else
#endif #endif
self->fd = open(name, flags, 0666); self->fd = open(name, flags, 0666);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (self->fd < 0) { if (self->fd < 0) {
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
if (widename != NULL) if (widename != NULL)
PyErr_SetFromErrnoWithUnicodeFilename(PyExc_IOError, widename); PyErr_SetFromErrnoWithUnicodeFilename(PyExc_IOError, widename);
else else
#endif #endif
PyErr_SetFromErrnoWithFilename(PyExc_IOError, name); PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
goto error; goto error;
} }
if(dircheck(self, name) < 0) if(dircheck(self, name) < 0)
goto error; goto error;
} }
if (PyObject_SetAttrString((PyObject *)self, "name", nameobj) < 0) if (PyObject_SetAttrString((PyObject *)self, "name", nameobj) < 0)
goto error; goto error;
if (append) { if (append) {
/* For consistent behaviour, we explicitly seek to the /* For consistent behaviour, we explicitly seek to the
end of file (otherwise, it might be done only on the end of file (otherwise, it might be done only on the
first write()). */ first write()). */
PyObject *pos = portable_lseek(self->fd, NULL, 2); PyObject *pos = portable_lseek(self->fd, NULL, 2);
if (pos == NULL) if (pos == NULL)
goto error; goto error;
Py_DECREF(pos); Py_DECREF(pos);
} }
goto done; goto done;
error: error:
ret = -1; ret = -1;
done: done:
Py_CLEAR(stringobj); Py_CLEAR(stringobj);
return ret; return ret;
} }
static int static int
fileio_traverse(fileio *self, visitproc visit, void *arg) fileio_traverse(fileio *self, visitproc visit, void *arg)
{ {
Py_VISIT(self->dict); Py_VISIT(self->dict);
return 0; return 0;
} }
static int static int
fileio_clear(fileio *self) fileio_clear(fileio *self)
{ {
Py_CLEAR(self->dict); Py_CLEAR(self->dict);
return 0; return 0;
} }
static void static void
fileio_dealloc(fileio *self) fileio_dealloc(fileio *self)
{ {
if (_PyIOBase_finalize((PyObject *) self) < 0) if (_PyIOBase_finalize((PyObject *) self) < 0)
return; return;
_PyObject_GC_UNTRACK(self); _PyObject_GC_UNTRACK(self);
if (self->weakreflist != NULL) if (self->weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject *) self); PyObject_ClearWeakRefs((PyObject *) self);
Py_CLEAR(self->dict); Py_CLEAR(self->dict);
Py_TYPE(self)->tp_free((PyObject *)self); Py_TYPE(self)->tp_free((PyObject *)self);
} }
static PyObject * static PyObject *
err_closed(void) err_closed(void)
{ {
PyErr_SetString(PyExc_ValueError, "I/O operation on closed file"); PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
return NULL; return NULL;
} }
static PyObject * static PyObject *
err_mode(char *action) err_mode(char *action)
{ {
PyErr_Format(PyExc_ValueError, "File not open for %s", action); PyErr_Format(PyExc_ValueError, "File not open for %s", action);
return NULL; return NULL;
} }
static PyObject * static PyObject *
fileio_fileno(fileio *self) fileio_fileno(fileio *self)
{ {
if (self->fd < 0) if (self->fd < 0)
return err_closed(); return err_closed();
return PyLong_FromLong((long) self->fd); return PyLong_FromLong((long) self->fd);
} }
static PyObject * static PyObject *
fileio_readable(fileio *self) fileio_readable(fileio *self)
{ {
if (self->fd < 0) if (self->fd < 0)
return err_closed(); return err_closed();
return PyBool_FromLong((long) self->readable); return PyBool_FromLong((long) self->readable);
} }
static PyObject * static PyObject *
fileio_writable(fileio *self) fileio_writable(fileio *self)
{ {
if (self->fd < 0) if (self->fd < 0)
return err_closed(); return err_closed();
return PyBool_FromLong((long) self->writable); return PyBool_FromLong((long) self->writable);
} }
static PyObject * static PyObject *
fileio_seekable(fileio *self) fileio_seekable(fileio *self)
{ {
if (self->fd < 0) if (self->fd < 0)
return err_closed(); return err_closed();
if (self->seekable < 0) { if (self->seekable < 0) {
PyObject *pos = portable_lseek(self->fd, NULL, SEEK_CUR); PyObject *pos = portable_lseek(self->fd, NULL, SEEK_CUR);
if (pos == NULL) { if (pos == NULL) {
PyErr_Clear(); PyErr_Clear();
self->seekable = 0; self->seekable = 0;
} else { } else {
Py_DECREF(pos); Py_DECREF(pos);
self->seekable = 1; self->seekable = 1;
} }
} }
return PyBool_FromLong((long) self->seekable); return PyBool_FromLong((long) self->seekable);
} }
static PyObject * static PyObject *
fileio_readinto(fileio *self, PyObject *args) fileio_readinto(fileio *self, PyObject *args)
{ {
Py_buffer pbuf; Py_buffer pbuf;
Py_ssize_t n; Py_ssize_t n;
if (self->fd < 0) if (self->fd < 0)
return err_closed(); return err_closed();
if (!self->readable) if (!self->readable)
return err_mode("reading"); return err_mode("reading");
if (!PyArg_ParseTuple(args, "w*", &pbuf)) if (!PyArg_ParseTuple(args, "w*", &pbuf))
return NULL; return NULL;
if (_PyVerify_fd(self->fd)) { if (_PyVerify_fd(self->fd)) {
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
errno = 0; errno = 0;
n = read(self->fd, pbuf.buf, pbuf.len); n = read(self->fd, pbuf.buf, pbuf.len);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
} else } else
n = -1; n = -1;
PyBuffer_Release(&pbuf); PyBuffer_Release(&pbuf);
if (n < 0) { if (n < 0) {
if (errno == EAGAIN) if (errno == EAGAIN)
Py_RETURN_NONE; Py_RETURN_NONE;
PyErr_SetFromErrno(PyExc_IOError); PyErr_SetFromErrno(PyExc_IOError);
return NULL; return NULL;
} }
return PyLong_FromSsize_t(n); return PyLong_FromSsize_t(n);
} }
static size_t static size_t
new_buffersize(fileio *self, size_t currentsize) new_buffersize(fileio *self, size_t currentsize)
{ {
#ifdef HAVE_FSTAT #ifdef HAVE_FSTAT
off_t pos, end; off_t pos, end;
struct stat st; struct stat st;
if (fstat(self->fd, &st) == 0) { if (fstat(self->fd, &st) == 0) {
end = st.st_size; end = st.st_size;
pos = lseek(self->fd, 0L, SEEK_CUR); pos = lseek(self->fd, 0L, SEEK_CUR);
/* Files claiming a size smaller than SMALLCHUNK may /* Files claiming a size smaller than SMALLCHUNK may
actually be streaming pseudo-files. In this case, we actually be streaming pseudo-files. In this case, we
apply the more aggressive algorithm below. apply the more aggressive algorithm below.
*/ */
if (end >= SMALLCHUNK && end >= pos && pos >= 0) { if (end >= SMALLCHUNK && end >= pos && pos >= 0) {
/* Add 1 so if the file were to grow we'd notice. */ /* Add 1 so if the file were to grow we'd notice. */
return currentsize + end - pos + 1; return currentsize + end - pos + 1;
} }
} }
#endif #endif
if (currentsize > SMALLCHUNK) { if (currentsize > SMALLCHUNK) {
/* Keep doubling until we reach BIGCHUNK; /* Keep doubling until we reach BIGCHUNK;
then keep adding BIGCHUNK. */ then keep adding BIGCHUNK. */
if (currentsize <= BIGCHUNK) if (currentsize <= BIGCHUNK)
return currentsize + currentsize; return currentsize + currentsize;
else else
return currentsize + BIGCHUNK; return currentsize + BIGCHUNK;
} }
return currentsize + SMALLCHUNK; return currentsize + SMALLCHUNK;
} }
static PyObject * static PyObject *
fileio_readall(fileio *self) fileio_readall(fileio *self)
{ {
PyObject *result; PyObject *result;
Py_ssize_t total = 0; Py_ssize_t total = 0;
int n; int n;
if (!_PyVerify_fd(self->fd)) if (!_PyVerify_fd(self->fd))
return PyErr_SetFromErrno(PyExc_IOError); return PyErr_SetFromErrno(PyExc_IOError);
result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK); result = PyBytes_FromStringAndSize(NULL, SMALLCHUNK);
if (result == NULL) if (result == NULL)
return NULL; return NULL;
while (1) { while (1) {
size_t newsize = new_buffersize(self, total); size_t newsize = new_buffersize(self, total);
if (newsize > PY_SSIZE_T_MAX || newsize <= 0) { if (newsize > PY_SSIZE_T_MAX || newsize <= 0) {
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
"unbounded read returned more bytes " "unbounded read returned more bytes "
"than a Python string can hold "); "than a Python string can hold ");
Py_DECREF(result); Py_DECREF(result);
return NULL; return NULL;
} }
if (PyBytes_GET_SIZE(result) < (Py_ssize_t)newsize) { if (PyBytes_GET_SIZE(result) < (Py_ssize_t)newsize) {
if (_PyBytes_Resize(&result, newsize) < 0) { if (_PyBytes_Resize(&result, newsize) < 0) {
if (total == 0) { if (total == 0) {
Py_DECREF(result); Py_DECREF(result);
return NULL; return NULL;
} }
PyErr_Clear(); PyErr_Clear();
break; break;
} }
} }
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
errno = 0; errno = 0;
n = read(self->fd, n = read(self->fd,
PyBytes_AS_STRING(result) + total, PyBytes_AS_STRING(result) + total,
newsize - total); newsize - total);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (n == 0) if (n == 0)
break; break;
if (n < 0) { if (n < 0) {
if (total > 0) if (total > 0)
break; break;
if (errno == EAGAIN) { if (errno == EAGAIN) {
Py_DECREF(result); Py_DECREF(result);
Py_RETURN_NONE; Py_RETURN_NONE;
} }
Py_DECREF(result); Py_DECREF(result);
PyErr_SetFromErrno(PyExc_IOError); PyErr_SetFromErrno(PyExc_IOError);
return NULL; return NULL;
} }
total += n; total += n;
} }
if (PyBytes_GET_SIZE(result) > total) { if (PyBytes_GET_SIZE(result) > total) {
if (_PyBytes_Resize(&result, total) < 0) { if (_PyBytes_Resize(&result, total) < 0) {
/* This should never happen, but just in case */ /* This should never happen, but just in case */
Py_DECREF(result); Py_DECREF(result);
return NULL; return NULL;
} }
} }
return result; return result;
} }
static PyObject * static PyObject *
fileio_read(fileio *self, PyObject *args) fileio_read(fileio *self, PyObject *args)
{ {
char *ptr; char *ptr;
Py_ssize_t n; Py_ssize_t n;
Py_ssize_t size = -1; Py_ssize_t size = -1;
PyObject *bytes; PyObject *bytes;
if (self->fd < 0) if (self->fd < 0)
return err_closed(); return err_closed();
if (!self->readable) if (!self->readable)
return err_mode("reading"); return err_mode("reading");
if (!PyArg_ParseTuple(args, "|O&", &_PyIO_ConvertSsize_t, &size)) if (!PyArg_ParseTuple(args, "|O&", &_PyIO_ConvertSsize_t, &size))
return NULL; return NULL;
if (size < 0) { if (size < 0) {
return fileio_readall(self); return fileio_readall(self);
} }
bytes = PyBytes_FromStringAndSize(NULL, size); bytes = PyBytes_FromStringAndSize(NULL, size);
if (bytes == NULL) if (bytes == NULL)
return NULL; return NULL;
ptr = PyBytes_AS_STRING(bytes); ptr = PyBytes_AS_STRING(bytes);
if (_PyVerify_fd(self->fd)) { if (_PyVerify_fd(self->fd)) {
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
errno = 0; errno = 0;
n = read(self->fd, ptr, size); n = read(self->fd, ptr, size);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
} else } else
n = -1; n = -1;
if (n < 0) { if (n < 0) {
Py_DECREF(bytes); Py_DECREF(bytes);
if (errno == EAGAIN) if (errno == EAGAIN)
Py_RETURN_NONE; Py_RETURN_NONE;
PyErr_SetFromErrno(PyExc_IOError); PyErr_SetFromErrno(PyExc_IOError);
return NULL; return NULL;
} }
if (n != size) { if (n != size) {
if (_PyBytes_Resize(&bytes, n) < 0) { if (_PyBytes_Resize(&bytes, n) < 0) {
Py_DECREF(bytes); Py_DECREF(bytes);
return NULL; return NULL;
} }
} }
return (PyObject *) bytes; return (PyObject *) bytes;
} }
static PyObject * static PyObject *
fileio_write(fileio *self, PyObject *args) fileio_write(fileio *self, PyObject *args)
{ {
Py_buffer pbuf; Py_buffer pbuf;
Py_ssize_t n; Py_ssize_t n;
if (self->fd < 0) if (self->fd < 0)
return err_closed(); return err_closed();
if (!self->writable) if (!self->writable)
return err_mode("writing"); return err_mode("writing");
if (!PyArg_ParseTuple(args, "y*", &pbuf)) if (!PyArg_ParseTuple(args, "y*", &pbuf))
return NULL; return NULL;
if (_PyVerify_fd(self->fd)) { if (_PyVerify_fd(self->fd)) {
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
errno = 0; errno = 0;
n = write(self->fd, pbuf.buf, pbuf.len); n = write(self->fd, pbuf.buf, pbuf.len);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
} else } else
n = -1; n = -1;
PyBuffer_Release(&pbuf); PyBuffer_Release(&pbuf);
if (n < 0) { if (n < 0) {
if (errno == EAGAIN) if (errno == EAGAIN)
Py_RETURN_NONE; Py_RETURN_NONE;
PyErr_SetFromErrno(PyExc_IOError); PyErr_SetFromErrno(PyExc_IOError);
return NULL; return NULL;
} }
return PyLong_FromSsize_t(n); return PyLong_FromSsize_t(n);
} }
/* XXX Windows support below is likely incomplete */ /* XXX Windows support below is likely incomplete */
...@@ -680,235 +680,235 @@ fileio_write(fileio *self, PyObject *args) ...@@ -680,235 +680,235 @@ fileio_write(fileio *self, PyObject *args)
static PyObject * static PyObject *
portable_lseek(int fd, PyObject *posobj, int whence) portable_lseek(int fd, PyObject *posobj, int whence)
{ {
Py_off_t pos, res; Py_off_t pos, res;
#ifdef SEEK_SET #ifdef SEEK_SET
/* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */ /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
switch (whence) { switch (whence) {
#if SEEK_SET != 0 #if SEEK_SET != 0
case 0: whence = SEEK_SET; break; case 0: whence = SEEK_SET; break;
#endif #endif
#if SEEK_CUR != 1 #if SEEK_CUR != 1
case 1: whence = SEEK_CUR; break; case 1: whence = SEEK_CUR; break;
#endif #endif
#if SEEK_END != 2 #if SEEK_END != 2
case 2: whence = SEEK_END; break; case 2: whence = SEEK_END; break;
#endif #endif
} }
#endif /* SEEK_SET */ #endif /* SEEK_SET */
if (posobj == NULL) if (posobj == NULL)
pos = 0; pos = 0;
else { else {
if(PyFloat_Check(posobj)) { if(PyFloat_Check(posobj)) {
PyErr_SetString(PyExc_TypeError, "an integer is required"); PyErr_SetString(PyExc_TypeError, "an integer is required");
return NULL; return NULL;
} }
#if defined(HAVE_LARGEFILE_SUPPORT) #if defined(HAVE_LARGEFILE_SUPPORT)
pos = PyLong_AsLongLong(posobj); pos = PyLong_AsLongLong(posobj);
#else #else
pos = PyLong_AsLong(posobj); pos = PyLong_AsLong(posobj);
#endif #endif
if (PyErr_Occurred()) if (PyErr_Occurred())
return NULL; return NULL;
} }
if (_PyVerify_fd(fd)) { if (_PyVerify_fd(fd)) {
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
#if defined(MS_WIN64) || defined(MS_WINDOWS) #if defined(MS_WIN64) || defined(MS_WINDOWS)
res = _lseeki64(fd, pos, whence); res = _lseeki64(fd, pos, whence);
#else #else
res = lseek(fd, pos, whence); res = lseek(fd, pos, whence);
#endif #endif
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
} else } else
res = -1; res = -1;
if (res < 0) if (res < 0)
return PyErr_SetFromErrno(PyExc_IOError); return PyErr_SetFromErrno(PyExc_IOError);
#if defined(HAVE_LARGEFILE_SUPPORT) #if defined(HAVE_LARGEFILE_SUPPORT)
return PyLong_FromLongLong(res); return PyLong_FromLongLong(res);
#else #else
return PyLong_FromLong(res); return PyLong_FromLong(res);
#endif #endif
} }
static PyObject * static PyObject *
fileio_seek(fileio *self, PyObject *args) fileio_seek(fileio *self, PyObject *args)
{ {
PyObject *posobj; PyObject *posobj;
int whence = 0; int whence = 0;
if (self->fd < 0) if (self->fd < 0)
return err_closed(); return err_closed();
if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence)) if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence))
return NULL; return NULL;
return portable_lseek(self->fd, posobj, whence); return portable_lseek(self->fd, posobj, whence);
} }
static PyObject * static PyObject *
fileio_tell(fileio *self, PyObject *args) fileio_tell(fileio *self, PyObject *args)
{ {
if (self->fd < 0) if (self->fd < 0)
return err_closed(); return err_closed();
return portable_lseek(self->fd, NULL, 1); return portable_lseek(self->fd, NULL, 1);
} }
#ifdef HAVE_FTRUNCATE #ifdef HAVE_FTRUNCATE
static PyObject * static PyObject *
fileio_truncate(fileio *self, PyObject *args) fileio_truncate(fileio *self, PyObject *args)
{ {
PyObject *posobj = NULL; /* the new size wanted by the user */ PyObject *posobj = NULL; /* the new size wanted by the user */
#ifndef MS_WINDOWS #ifndef MS_WINDOWS
Py_off_t pos; Py_off_t pos;
#endif #endif
int ret; int ret;
int fd; int fd;
fd = self->fd; fd = self->fd;
if (fd < 0) if (fd < 0)
return err_closed(); return err_closed();
if (!self->writable) if (!self->writable)
return err_mode("writing"); return err_mode("writing");
if (!PyArg_ParseTuple(args, "|O", &posobj)) if (!PyArg_ParseTuple(args, "|O", &posobj))
return NULL; return NULL;
if (posobj == Py_None || posobj == NULL) { if (posobj == Py_None || posobj == NULL) {
/* Get the current position. */ /* Get the current position. */
posobj = portable_lseek(fd, NULL, 1); posobj = portable_lseek(fd, NULL, 1);
if (posobj == NULL) if (posobj == NULL)
return NULL; return NULL;
} }
else { else {
Py_INCREF(posobj); Py_INCREF(posobj);
} }
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
/* MS _chsize doesn't work if newsize doesn't fit in 32 bits, /* MS _chsize doesn't work if newsize doesn't fit in 32 bits,
so don't even try using it. */ so don't even try using it. */
{ {
PyObject *oldposobj, *tempposobj; PyObject *oldposobj, *tempposobj;
HANDLE hFile; HANDLE hFile;
/* we save the file pointer position */ /* we save the file pointer position */
oldposobj = portable_lseek(fd, NULL, 1); oldposobj = portable_lseek(fd, NULL, 1);
if (oldposobj == NULL) { if (oldposobj == NULL) {
Py_DECREF(posobj); Py_DECREF(posobj);
return NULL; return NULL;
} }
/* we then move to the truncation position */ /* we then move to the truncation position */
tempposobj = portable_lseek(fd, posobj, 0); tempposobj = portable_lseek(fd, posobj, 0);
if (tempposobj == NULL) { if (tempposobj == NULL) {
Py_DECREF(oldposobj); Py_DECREF(oldposobj);
Py_DECREF(posobj); Py_DECREF(posobj);
return NULL; return NULL;
} }
Py_DECREF(tempposobj); Py_DECREF(tempposobj);
/* Truncate. Note that this may grow the file! */ /* Truncate. Note that this may grow the file! */
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
errno = 0; errno = 0;
hFile = (HANDLE)_get_osfhandle(fd); hFile = (HANDLE)_get_osfhandle(fd);
ret = hFile == (HANDLE)-1; /* testing for INVALID_HANDLE value */ ret = hFile == (HANDLE)-1; /* testing for INVALID_HANDLE value */
if (ret == 0) { if (ret == 0) {
ret = SetEndOfFile(hFile) == 0; ret = SetEndOfFile(hFile) == 0;
if (ret) if (ret)
errno = EACCES; errno = EACCES;
} }
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
/* we restore the file pointer position in any case */ /* we restore the file pointer position in any case */
tempposobj = portable_lseek(fd, oldposobj, 0); tempposobj = portable_lseek(fd, oldposobj, 0);
Py_DECREF(oldposobj); Py_DECREF(oldposobj);
if (tempposobj == NULL) { if (tempposobj == NULL) {
Py_DECREF(posobj); Py_DECREF(posobj);
return NULL; return NULL;
} }
Py_DECREF(tempposobj); Py_DECREF(tempposobj);
} }
#else #else
#if defined(HAVE_LARGEFILE_SUPPORT) #if defined(HAVE_LARGEFILE_SUPPORT)
pos = PyLong_AsLongLong(posobj); pos = PyLong_AsLongLong(posobj);
#else #else
pos = PyLong_AsLong(posobj); pos = PyLong_AsLong(posobj);
#endif #endif
if (PyErr_Occurred()){ if (PyErr_Occurred()){
Py_DECREF(posobj); Py_DECREF(posobj);
return NULL; return NULL;
} }
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
errno = 0; errno = 0;
ret = ftruncate(fd, pos); ret = ftruncate(fd, pos);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
#endif /* !MS_WINDOWS */ #endif /* !MS_WINDOWS */
if (ret != 0) { if (ret != 0) {
Py_DECREF(posobj); Py_DECREF(posobj);
PyErr_SetFromErrno(PyExc_IOError); PyErr_SetFromErrno(PyExc_IOError);
return NULL; return NULL;
} }
return posobj; return posobj;
} }
#endif /* HAVE_FTRUNCATE */ #endif /* HAVE_FTRUNCATE */
static char * static char *
mode_string(fileio *self) mode_string(fileio *self)
{ {
if (self->readable) { if (self->readable) {
if (self->writable) if (self->writable)
return "rb+"; return "rb+";
else else
return "rb"; return "rb";
} }
else else
return "wb"; return "wb";
} }
static PyObject * static PyObject *
fileio_repr(fileio *self) fileio_repr(fileio *self)
{ {
PyObject *nameobj, *res; PyObject *nameobj, *res;
if (self->fd < 0) if (self->fd < 0)
return PyUnicode_FromFormat("<_io.FileIO [closed]>"); return PyUnicode_FromFormat("<_io.FileIO [closed]>");
nameobj = PyObject_GetAttrString((PyObject *) self, "name"); nameobj = PyObject_GetAttrString((PyObject *) self, "name");
if (nameobj == NULL) { if (nameobj == NULL) {
if (PyErr_ExceptionMatches(PyExc_AttributeError)) if (PyErr_ExceptionMatches(PyExc_AttributeError))
PyErr_Clear(); PyErr_Clear();
else else
return NULL; return NULL;
res = PyUnicode_FromFormat("<_io.FileIO fd=%d mode='%s'>", res = PyUnicode_FromFormat("<_io.FileIO fd=%d mode='%s'>",
self->fd, mode_string(self)); self->fd, mode_string(self));
} }
else { else {
res = PyUnicode_FromFormat("<_io.FileIO name=%R mode='%s'>", res = PyUnicode_FromFormat("<_io.FileIO name=%R mode='%s'>",
nameobj, mode_string(self)); nameobj, mode_string(self));
Py_DECREF(nameobj); Py_DECREF(nameobj);
} }
return res; return res;
} }
static PyObject * static PyObject *
fileio_isatty(fileio *self) fileio_isatty(fileio *self)
{ {
long res; long res;
if (self->fd < 0) if (self->fd < 0)
return err_closed(); return err_closed();
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
res = isatty(self->fd); res = isatty(self->fd);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
return PyBool_FromLong(res); return PyBool_FromLong(res);
} }
...@@ -916,7 +916,7 @@ PyDoc_STRVAR(fileio_doc, ...@@ -916,7 +916,7 @@ PyDoc_STRVAR(fileio_doc,
"file(name: str[, mode: str]) -> file IO object\n" "file(name: str[, mode: str]) -> file IO object\n"
"\n" "\n"
"Open a file. The mode can be 'r', 'w' or 'a' for reading (default),\n" "Open a file. The mode can be 'r', 'w' or 'a' for reading (default),\n"
"writing or appending. The file will be created if it doesn't exist\n" "writing or appending. The file will be created if it doesn't exist\n"
"when opened for writing or appending; it will be truncated when\n" "when opened for writing or appending; it will be truncated when\n"
"opened for writing. Add a '+' to the mode to allow simultaneous\n" "opened for writing. Add a '+' to the mode to allow simultaneous\n"
"reading and writing."); "reading and writing.");
...@@ -958,14 +958,14 @@ PyDoc_STRVAR(seek_doc, ...@@ -958,14 +958,14 @@ PyDoc_STRVAR(seek_doc,
#ifdef HAVE_FTRUNCATE #ifdef HAVE_FTRUNCATE
PyDoc_STRVAR(truncate_doc, PyDoc_STRVAR(truncate_doc,
"truncate([size: int]) -> None. Truncate the file to at most size bytes.\n" "truncate([size: int]) -> None. Truncate the file to at most size bytes.\n"
"\n" "\n"
"Size defaults to the current file position, as returned by tell()." "Size defaults to the current file position, as returned by tell()."
"The current file position is changed to the value of size."); "The current file position is changed to the value of size.");
#endif #endif
PyDoc_STRVAR(tell_doc, PyDoc_STRVAR(tell_doc,
"tell() -> int. Current file position"); "tell() -> int. Current file position");
PyDoc_STRVAR(readinto_doc, PyDoc_STRVAR(readinto_doc,
"readinto() -> Same as RawIOBase.readinto()."); "readinto() -> Same as RawIOBase.readinto().");
...@@ -989,22 +989,22 @@ PyDoc_STRVAR(writable_doc, ...@@ -989,22 +989,22 @@ PyDoc_STRVAR(writable_doc,
"writable() -> bool. True if file was opened in a write mode."); "writable() -> bool. True if file was opened in a write mode.");
static PyMethodDef fileio_methods[] = { static PyMethodDef fileio_methods[] = {
{"read", (PyCFunction)fileio_read, METH_VARARGS, read_doc}, {"read", (PyCFunction)fileio_read, METH_VARARGS, read_doc},
{"readall", (PyCFunction)fileio_readall, METH_NOARGS, readall_doc}, {"readall", (PyCFunction)fileio_readall, METH_NOARGS, readall_doc},
{"readinto", (PyCFunction)fileio_readinto, METH_VARARGS, readinto_doc}, {"readinto", (PyCFunction)fileio_readinto, METH_VARARGS, readinto_doc},
{"write", (PyCFunction)fileio_write, METH_VARARGS, write_doc}, {"write", (PyCFunction)fileio_write, METH_VARARGS, write_doc},
{"seek", (PyCFunction)fileio_seek, METH_VARARGS, seek_doc}, {"seek", (PyCFunction)fileio_seek, METH_VARARGS, seek_doc},
{"tell", (PyCFunction)fileio_tell, METH_VARARGS, tell_doc}, {"tell", (PyCFunction)fileio_tell, METH_VARARGS, tell_doc},
#ifdef HAVE_FTRUNCATE #ifdef HAVE_FTRUNCATE
{"truncate", (PyCFunction)fileio_truncate, METH_VARARGS, truncate_doc}, {"truncate", (PyCFunction)fileio_truncate, METH_VARARGS, truncate_doc},
#endif #endif
{"close", (PyCFunction)fileio_close, METH_NOARGS, close_doc}, {"close", (PyCFunction)fileio_close, METH_NOARGS, close_doc},
{"seekable", (PyCFunction)fileio_seekable, METH_NOARGS, seekable_doc}, {"seekable", (PyCFunction)fileio_seekable, METH_NOARGS, seekable_doc},
{"readable", (PyCFunction)fileio_readable, METH_NOARGS, readable_doc}, {"readable", (PyCFunction)fileio_readable, METH_NOARGS, readable_doc},
{"writable", (PyCFunction)fileio_writable, METH_NOARGS, writable_doc}, {"writable", (PyCFunction)fileio_writable, METH_NOARGS, writable_doc},
{"fileno", (PyCFunction)fileio_fileno, METH_NOARGS, fileno_doc}, {"fileno", (PyCFunction)fileio_fileno, METH_NOARGS, fileno_doc},
{"isatty", (PyCFunction)fileio_isatty, METH_NOARGS, isatty_doc}, {"isatty", (PyCFunction)fileio_isatty, METH_NOARGS, isatty_doc},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
/* 'closed' and 'mode' are attributes for backwards compatibility reasons. */ /* 'closed' and 'mode' are attributes for backwards compatibility reasons. */
...@@ -1012,68 +1012,68 @@ static PyMethodDef fileio_methods[] = { ...@@ -1012,68 +1012,68 @@ static PyMethodDef fileio_methods[] = {
static PyObject * static PyObject *
get_closed(fileio *self, void *closure) get_closed(fileio *self, void *closure)
{ {
return PyBool_FromLong((long)(self->fd < 0)); return PyBool_FromLong((long)(self->fd < 0));
} }
static PyObject * static PyObject *
get_closefd(fileio *self, void *closure) get_closefd(fileio *self, void *closure)
{ {
return PyBool_FromLong((long)(self->closefd)); return PyBool_FromLong((long)(self->closefd));
} }
static PyObject * static PyObject *
get_mode(fileio *self, void *closure) get_mode(fileio *self, void *closure)
{ {
return PyUnicode_FromString(mode_string(self)); return PyUnicode_FromString(mode_string(self));
} }
static PyGetSetDef fileio_getsetlist[] = { static PyGetSetDef fileio_getsetlist[] = {
{"closed", (getter)get_closed, NULL, "True if the file is closed"}, {"closed", (getter)get_closed, NULL, "True if the file is closed"},
{"closefd", (getter)get_closefd, NULL, {"closefd", (getter)get_closefd, NULL,
"True if the file descriptor will be closed"}, "True if the file descriptor will be closed"},
{"mode", (getter)get_mode, NULL, "String giving the file mode"}, {"mode", (getter)get_mode, NULL, "String giving the file mode"},
{NULL}, {NULL},
}; };
PyTypeObject PyFileIO_Type = { PyTypeObject PyFileIO_Type = {
PyVarObject_HEAD_INIT(NULL, 0) PyVarObject_HEAD_INIT(NULL, 0)
"_io.FileIO", "_io.FileIO",
sizeof(fileio), sizeof(fileio),
0, 0,
(destructor)fileio_dealloc, /* tp_dealloc */ (destructor)fileio_dealloc, /* tp_dealloc */
0, /* tp_print */ 0, /* tp_print */
0, /* tp_getattr */ 0, /* tp_getattr */
0, /* tp_setattr */ 0, /* tp_setattr */
0, /* tp_reserved */ 0, /* tp_reserved */
(reprfunc)fileio_repr, /* tp_repr */ (reprfunc)fileio_repr, /* tp_repr */
0, /* tp_as_number */ 0, /* tp_as_number */
0, /* tp_as_sequence */ 0, /* tp_as_sequence */
0, /* tp_as_mapping */ 0, /* tp_as_mapping */
0, /* tp_hash */ 0, /* tp_hash */
0, /* tp_call */ 0, /* tp_call */
0, /* tp_str */ 0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */ PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */ 0, /* tp_setattro */
0, /* tp_as_buffer */ 0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
| Py_TPFLAGS_HAVE_GC, /* tp_flags */ | Py_TPFLAGS_HAVE_GC, /* tp_flags */
fileio_doc, /* tp_doc */ fileio_doc, /* tp_doc */
(traverseproc)fileio_traverse, /* tp_traverse */ (traverseproc)fileio_traverse, /* tp_traverse */
(inquiry)fileio_clear, /* tp_clear */ (inquiry)fileio_clear, /* tp_clear */
0, /* tp_richcompare */ 0, /* tp_richcompare */
offsetof(fileio, weakreflist), /* tp_weaklistoffset */ offsetof(fileio, weakreflist), /* tp_weaklistoffset */
0, /* tp_iter */ 0, /* tp_iter */
0, /* tp_iternext */ 0, /* tp_iternext */
fileio_methods, /* tp_methods */ fileio_methods, /* tp_methods */
0, /* tp_members */ 0, /* tp_members */
fileio_getsetlist, /* tp_getset */ fileio_getsetlist, /* tp_getset */
0, /* tp_base */ 0, /* tp_base */
0, /* tp_dict */ 0, /* tp_dict */
0, /* tp_descr_get */ 0, /* tp_descr_get */
0, /* tp_descr_set */ 0, /* tp_descr_set */
offsetof(fileio, dict), /* tp_dictoffset */ offsetof(fileio, dict), /* tp_dictoffset */
fileio_init, /* tp_init */ fileio_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */ PyType_GenericAlloc, /* tp_alloc */
fileio_new, /* tp_new */ fileio_new, /* tp_new */
PyObject_GC_Del, /* tp_free */ PyObject_GC_Del, /* tp_free */
}; };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment