Issue #5768: Change to Unicode output logic and test case for same.
[python.git] / Modules / _fileio.c
blob409abf6e0faa3f7090956acc45af61ffbc938d2d
1 /* Author: Daniel Stutzbach */
3 #define PY_SSIZE_T_CLEAN
4 #include "Python.h"
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 #include <stddef.h> /* For offsetof */
11 * Known likely problems:
13 * - Files larger then 2**32-1
14 * - Files with unicode filenames
15 * - Passing numbers greater than 2**32-1 when an integer is expected
16 * - Making it work on Windows and other oddball platforms
18 * To Do:
20 * - autoconfify header file inclusion
23 #ifdef MS_WINDOWS
24 /* can simulate truncate with Win32 API functions; see file_truncate */
25 #define HAVE_FTRUNCATE
26 #define WIN32_LEAN_AND_MEAN
27 #include <windows.h>
28 #endif
30 typedef struct {
31 PyObject_HEAD
32 int fd;
33 unsigned readable : 1;
34 unsigned writable : 1;
35 int seekable : 2; /* -1 means unknown */
36 int closefd : 1;
37 PyObject *weakreflist;
38 } PyFileIOObject;
40 PyTypeObject PyFileIO_Type;
42 #define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type))
44 static PyObject *
45 portable_lseek(int fd, PyObject *posobj, int whence);
47 /* Returns 0 on success, errno (which is < 0) on failure. */
48 static int
49 internal_close(PyFileIOObject *self)
51 int save_errno = 0;
52 if (self->fd >= 0) {
53 int fd = self->fd;
54 self->fd = -1;
55 Py_BEGIN_ALLOW_THREADS
56 if (close(fd) < 0)
57 save_errno = errno;
58 Py_END_ALLOW_THREADS
60 return save_errno;
63 static PyObject *
64 fileio_close(PyFileIOObject *self)
66 if (!self->closefd) {
67 self->fd = -1;
68 Py_RETURN_NONE;
70 errno = internal_close(self);
71 if (errno < 0) {
72 PyErr_SetFromErrno(PyExc_IOError);
73 return NULL;
76 Py_RETURN_NONE;
79 static PyObject *
80 fileio_new(PyTypeObject *type, PyObject *args, PyObject *kews)
82 PyFileIOObject *self;
84 assert(type != NULL && type->tp_alloc != NULL);
86 self = (PyFileIOObject *) type->tp_alloc(type, 0);
87 if (self != NULL) {
88 self->fd = -1;
89 self->readable = 0;
90 self->writable = 0;
91 self->seekable = -1;
92 self->closefd = 1;
93 self->weakreflist = NULL;
96 return (PyObject *) self;
99 /* On Unix, open will succeed for directories.
100 In Python, there should be no file objects referring to
101 directories, so we need a check. */
103 static int
104 dircheck(PyFileIOObject* self, char *name)
106 #if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR)
107 struct stat buf;
108 if (self->fd < 0)
109 return 0;
110 if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) {
111 char *msg = strerror(EISDIR);
112 PyObject *exc;
113 internal_close(self);
115 exc = PyObject_CallFunction(PyExc_IOError, "(iss)",
116 EISDIR, msg, name);
117 PyErr_SetObject(PyExc_IOError, exc);
118 Py_XDECREF(exc);
119 return -1;
121 #endif
122 return 0;
125 static int
126 check_fd(int fd)
128 #if defined(HAVE_FSTAT)
129 struct stat buf;
130 if (!_PyVerify_fd(fd) || (fstat(fd, &buf) < 0 && errno == EBADF)) {
131 PyObject *exc;
132 char *msg = strerror(EBADF);
133 exc = PyObject_CallFunction(PyExc_OSError, "(is)",
134 EBADF, msg);
135 PyErr_SetObject(PyExc_OSError, exc);
136 Py_XDECREF(exc);
137 return -1;
139 #endif
140 return 0;
144 static int
145 fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
147 PyFileIOObject *self = (PyFileIOObject *) oself;
148 static char *kwlist[] = {"file", "mode", "closefd", NULL};
149 char *name = NULL;
150 char *mode = "r";
151 char *s;
152 #ifdef MS_WINDOWS
153 Py_UNICODE *widename = NULL;
154 #endif
155 int ret = 0;
156 int rwa = 0, plus = 0, append = 0;
157 int flags = 0;
158 int fd = -1;
159 int closefd = 1;
161 assert(PyFileIO_Check(oself));
162 if (self->fd >= 0) {
163 /* Have to close the existing file first. */
164 if (internal_close(self) < 0)
165 return -1;
168 if (PyArg_ParseTupleAndKeywords(args, kwds, "i|si:fileio",
169 kwlist, &fd, &mode, &closefd)) {
170 if (fd < 0) {
171 PyErr_SetString(PyExc_ValueError,
172 "Negative filedescriptor");
173 return -1;
175 if (check_fd(fd))
176 return -1;
178 else {
179 PyErr_Clear();
181 #ifdef Py_WIN_WIDE_FILENAMES
182 if (GetVersion() < 0x80000000) {
183 /* On NT, so wide API available */
184 PyObject *po;
185 if (PyArg_ParseTupleAndKeywords(args, kwds, "U|si:fileio",
186 kwlist, &po, &mode, &closefd)
188 widename = PyUnicode_AS_UNICODE(po);
189 } else {
190 /* Drop the argument parsing error as narrow
191 strings are also valid. */
192 PyErr_Clear();
195 if (widename == NULL)
196 #endif
198 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:fileio",
199 kwlist,
200 Py_FileSystemDefaultEncoding,
201 &name, &mode, &closefd))
202 return -1;
206 s = mode;
207 while (*s) {
208 switch (*s++) {
209 case 'r':
210 if (rwa) {
211 bad_mode:
212 PyErr_SetString(PyExc_ValueError,
213 "Must have exactly one of read/write/append mode");
214 goto error;
216 rwa = 1;
217 self->readable = 1;
218 break;
219 case 'w':
220 if (rwa)
221 goto bad_mode;
222 rwa = 1;
223 self->writable = 1;
224 flags |= O_CREAT | O_TRUNC;
225 break;
226 case 'a':
227 if (rwa)
228 goto bad_mode;
229 rwa = 1;
230 self->writable = 1;
231 flags |= O_CREAT;
232 append = 1;
233 break;
234 case 'b':
235 break;
236 case '+':
237 if (plus)
238 goto bad_mode;
239 self->readable = self->writable = 1;
240 plus = 1;
241 break;
242 default:
243 PyErr_Format(PyExc_ValueError,
244 "invalid mode: %.200s", mode);
245 goto error;
249 if (!rwa)
250 goto bad_mode;
252 if (self->readable && self->writable)
253 flags |= O_RDWR;
254 else if (self->readable)
255 flags |= O_RDONLY;
256 else
257 flags |= O_WRONLY;
259 #ifdef O_BINARY
260 flags |= O_BINARY;
261 #endif
263 #ifdef O_APPEND
264 if (append)
265 flags |= O_APPEND;
266 #endif
268 if (fd >= 0) {
269 self->fd = fd;
270 self->closefd = closefd;
272 else {
273 self->closefd = 1;
274 if (!closefd) {
275 PyErr_SetString(PyExc_ValueError,
276 "Cannot use closefd=False with file name");
277 goto error;
280 Py_BEGIN_ALLOW_THREADS
281 errno = 0;
282 #ifdef MS_WINDOWS
283 if (widename != NULL)
284 self->fd = _wopen(widename, flags, 0666);
285 else
286 #endif
287 self->fd = open(name, flags, 0666);
288 Py_END_ALLOW_THREADS
289 if (self->fd < 0) {
290 #ifdef MS_WINDOWS
291 if (widename != NULL)
292 PyErr_SetFromErrnoWithUnicodeFilename(PyExc_IOError, widename);
293 else
294 #endif
295 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
296 goto error;
298 if(dircheck(self, name) < 0)
299 goto error;
302 if (append) {
303 /* For consistent behaviour, we explicitly seek to the
304 end of file (otherwise, it might be done only on the
305 first write()). */
306 PyObject *pos = portable_lseek(self->fd, NULL, 2);
307 if (pos == NULL)
308 goto error;
309 Py_DECREF(pos);
312 goto done;
314 error:
315 ret = -1;
317 done:
318 PyMem_Free(name);
319 return ret;
322 static void
323 fileio_dealloc(PyFileIOObject *self)
325 if (self->weakreflist != NULL)
326 PyObject_ClearWeakRefs((PyObject *) self);
328 if (self->fd >= 0 && self->closefd) {
329 errno = internal_close(self);
330 if (errno < 0) {
331 PySys_WriteStderr("close failed: [Errno %d] %s\n",
332 errno, strerror(errno));
336 Py_TYPE(self)->tp_free((PyObject *)self);
339 static PyObject *
340 err_closed(void)
342 PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
343 return NULL;
346 static PyObject *
347 err_mode(char *action)
349 PyErr_Format(PyExc_ValueError, "File not open for %s", action);
350 return NULL;
353 static PyObject *
354 fileio_fileno(PyFileIOObject *self)
356 if (self->fd < 0)
357 return err_closed();
358 return PyInt_FromLong((long) self->fd);
361 static PyObject *
362 fileio_readable(PyFileIOObject *self)
364 if (self->fd < 0)
365 return err_closed();
366 return PyBool_FromLong((long) self->readable);
369 static PyObject *
370 fileio_writable(PyFileIOObject *self)
372 if (self->fd < 0)
373 return err_closed();
374 return PyBool_FromLong((long) self->writable);
377 static PyObject *
378 fileio_seekable(PyFileIOObject *self)
380 if (self->fd < 0)
381 return err_closed();
382 if (self->seekable < 0) {
383 int ret;
384 Py_BEGIN_ALLOW_THREADS
385 ret = lseek(self->fd, 0, SEEK_CUR);
386 Py_END_ALLOW_THREADS
387 if (ret < 0)
388 self->seekable = 0;
389 else
390 self->seekable = 1;
392 return PyBool_FromLong((long) self->seekable);
395 static PyObject *
396 fileio_readinto(PyFileIOObject *self, PyObject *args)
398 Py_buffer pbuf;
399 Py_ssize_t n;
401 if (self->fd < 0)
402 return err_closed();
403 if (!self->readable)
404 return err_mode("reading");
406 if (!PyArg_ParseTuple(args, "w*", &pbuf))
407 return NULL;
409 Py_BEGIN_ALLOW_THREADS
410 errno = 0;
411 n = read(self->fd, pbuf.buf, pbuf.len);
412 Py_END_ALLOW_THREADS
413 PyBuffer_Release(&pbuf);
414 if (n < 0) {
415 if (errno == EAGAIN)
416 Py_RETURN_NONE;
417 PyErr_SetFromErrno(PyExc_IOError);
418 return NULL;
421 return PyLong_FromSsize_t(n);
424 #define DEFAULT_BUFFER_SIZE (8*1024)
426 static PyObject *
427 fileio_readall(PyFileIOObject *self)
429 PyObject *result;
430 Py_ssize_t total = 0;
431 int n;
433 result = PyString_FromStringAndSize(NULL, DEFAULT_BUFFER_SIZE);
434 if (result == NULL)
435 return NULL;
437 while (1) {
438 Py_ssize_t newsize = total + DEFAULT_BUFFER_SIZE;
439 if (PyString_GET_SIZE(result) < newsize) {
440 if (_PyString_Resize(&result, newsize) < 0) {
441 if (total == 0) {
442 Py_DECREF(result);
443 return NULL;
445 PyErr_Clear();
446 break;
449 Py_BEGIN_ALLOW_THREADS
450 errno = 0;
451 n = read(self->fd,
452 PyString_AS_STRING(result) + total,
453 newsize - total);
454 Py_END_ALLOW_THREADS
455 if (n == 0)
456 break;
457 if (n < 0) {
458 if (total > 0)
459 break;
460 if (errno == EAGAIN) {
461 Py_DECREF(result);
462 Py_RETURN_NONE;
464 Py_DECREF(result);
465 PyErr_SetFromErrno(PyExc_IOError);
466 return NULL;
468 total += n;
471 if (PyString_GET_SIZE(result) > total) {
472 if (_PyString_Resize(&result, total) < 0) {
473 /* This should never happen, but just in case */
474 Py_DECREF(result);
475 return NULL;
478 return result;
481 static PyObject *
482 fileio_read(PyFileIOObject *self, PyObject *args)
484 char *ptr;
485 Py_ssize_t n;
486 Py_ssize_t size = -1;
487 PyObject *bytes;
489 if (self->fd < 0)
490 return err_closed();
491 if (!self->readable)
492 return err_mode("reading");
494 if (!PyArg_ParseTuple(args, "|n", &size))
495 return NULL;
497 if (size < 0) {
498 return fileio_readall(self);
501 bytes = PyString_FromStringAndSize(NULL, size);
502 if (bytes == NULL)
503 return NULL;
504 ptr = PyString_AS_STRING(bytes);
506 Py_BEGIN_ALLOW_THREADS
507 errno = 0;
508 n = read(self->fd, ptr, size);
509 Py_END_ALLOW_THREADS
511 if (n < 0) {
512 if (errno == EAGAIN)
513 Py_RETURN_NONE;
514 PyErr_SetFromErrno(PyExc_IOError);
515 return NULL;
518 if (n != size) {
519 if (_PyString_Resize(&bytes, n) < 0) {
520 Py_DECREF(bytes);
521 return NULL;
525 return (PyObject *) bytes;
528 static PyObject *
529 fileio_write(PyFileIOObject *self, PyObject *args)
531 Py_buffer pbuf;
532 Py_ssize_t n;
534 if (self->fd < 0)
535 return err_closed();
536 if (!self->writable)
537 return err_mode("writing");
539 if (!PyArg_ParseTuple(args, "s*", &pbuf))
540 return NULL;
542 Py_BEGIN_ALLOW_THREADS
543 errno = 0;
544 n = write(self->fd, pbuf.buf, pbuf.len);
545 Py_END_ALLOW_THREADS
547 PyBuffer_Release(&pbuf);
549 if (n < 0) {
550 if (errno == EAGAIN)
551 Py_RETURN_NONE;
552 PyErr_SetFromErrno(PyExc_IOError);
553 return NULL;
556 return PyLong_FromSsize_t(n);
559 /* XXX Windows support below is likely incomplete */
561 #if defined(MS_WIN64) || defined(MS_WINDOWS)
562 typedef PY_LONG_LONG Py_off_t;
563 #else
564 typedef off_t Py_off_t;
565 #endif
567 /* Cribbed from posix_lseek() */
568 static PyObject *
569 portable_lseek(int fd, PyObject *posobj, int whence)
571 Py_off_t pos, res;
573 #ifdef SEEK_SET
574 /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
575 switch (whence) {
576 #if SEEK_SET != 0
577 case 0: whence = SEEK_SET; break;
578 #endif
579 #if SEEK_CUR != 1
580 case 1: whence = SEEK_CUR; break;
581 #endif
582 #if SEEK_END != 2
583 case 2: whence = SEEK_END; break;
584 #endif
586 #endif /* SEEK_SET */
588 if (posobj == NULL)
589 pos = 0;
590 else {
591 if(PyFloat_Check(posobj)) {
592 PyErr_SetString(PyExc_TypeError, "an integer is required");
593 return NULL;
595 #if defined(HAVE_LARGEFILE_SUPPORT)
596 pos = PyLong_AsLongLong(posobj);
597 #else
598 pos = PyLong_AsLong(posobj);
599 #endif
600 if (PyErr_Occurred())
601 return NULL;
604 Py_BEGIN_ALLOW_THREADS
605 #if defined(MS_WIN64) || defined(MS_WINDOWS)
606 res = _lseeki64(fd, pos, whence);
607 #else
608 res = lseek(fd, pos, whence);
609 #endif
610 Py_END_ALLOW_THREADS
611 if (res < 0)
612 return PyErr_SetFromErrno(PyExc_IOError);
614 #if defined(HAVE_LARGEFILE_SUPPORT)
615 return PyLong_FromLongLong(res);
616 #else
617 return PyLong_FromLong(res);
618 #endif
621 static PyObject *
622 fileio_seek(PyFileIOObject *self, PyObject *args)
624 PyObject *posobj;
625 int whence = 0;
627 if (self->fd < 0)
628 return err_closed();
630 if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence))
631 return NULL;
633 return portable_lseek(self->fd, posobj, whence);
636 static PyObject *
637 fileio_tell(PyFileIOObject *self, PyObject *args)
639 if (self->fd < 0)
640 return err_closed();
642 return portable_lseek(self->fd, NULL, 1);
645 #ifdef HAVE_FTRUNCATE
646 static PyObject *
647 fileio_truncate(PyFileIOObject *self, PyObject *args)
649 PyObject *posobj = NULL;
650 Py_off_t pos;
651 int ret;
652 int fd;
654 fd = self->fd;
655 if (fd < 0)
656 return err_closed();
657 if (!self->writable)
658 return err_mode("writing");
660 if (!PyArg_ParseTuple(args, "|O", &posobj))
661 return NULL;
663 if (posobj == Py_None || posobj == NULL) {
664 /* Get the current position. */
665 posobj = portable_lseek(fd, NULL, 1);
666 if (posobj == NULL)
667 return NULL;
669 else {
670 /* Move to the position to be truncated. */
671 posobj = portable_lseek(fd, posobj, 0);
674 #if defined(HAVE_LARGEFILE_SUPPORT)
675 pos = PyLong_AsLongLong(posobj);
676 #else
677 pos = PyLong_AsLong(posobj);
678 #endif
679 if (PyErr_Occurred())
680 return NULL;
682 #ifdef MS_WINDOWS
683 /* MS _chsize doesn't work if newsize doesn't fit in 32 bits,
684 so don't even try using it. */
686 HANDLE hFile;
688 /* Truncate. Note that this may grow the file! */
689 Py_BEGIN_ALLOW_THREADS
690 errno = 0;
691 hFile = (HANDLE)_get_osfhandle(fd);
692 ret = hFile == (HANDLE)-1;
693 if (ret == 0) {
694 ret = SetEndOfFile(hFile) == 0;
695 if (ret)
696 errno = EACCES;
698 Py_END_ALLOW_THREADS
700 #else
701 Py_BEGIN_ALLOW_THREADS
702 errno = 0;
703 ret = ftruncate(fd, pos);
704 Py_END_ALLOW_THREADS
705 #endif /* !MS_WINDOWS */
707 if (ret != 0) {
708 PyErr_SetFromErrno(PyExc_IOError);
709 return NULL;
712 return posobj;
714 #endif
716 static char *
717 mode_string(PyFileIOObject *self)
719 if (self->readable) {
720 if (self->writable)
721 return "rb+";
722 else
723 return "rb";
725 else
726 return "wb";
729 static PyObject *
730 fileio_repr(PyFileIOObject *self)
732 if (self->fd < 0)
733 return PyString_FromFormat("_fileio._FileIO(-1)");
735 return PyString_FromFormat("_fileio._FileIO(%d, '%s')",
736 self->fd, mode_string(self));
739 static PyObject *
740 fileio_isatty(PyFileIOObject *self)
742 long res;
744 if (self->fd < 0)
745 return err_closed();
746 Py_BEGIN_ALLOW_THREADS
747 res = isatty(self->fd);
748 Py_END_ALLOW_THREADS
749 return PyBool_FromLong(res);
753 PyDoc_STRVAR(fileio_doc,
754 "file(name: str[, mode: str]) -> file IO object\n"
755 "\n"
756 "Open a file. The mode can be 'r', 'w' or 'a' for reading (default),\n"
757 "writing or appending. The file will be created if it doesn't exist\n"
758 "when opened for writing or appending; it will be truncated when\n"
759 "opened for writing. Add a '+' to the mode to allow simultaneous\n"
760 "reading and writing.");
762 PyDoc_STRVAR(read_doc,
763 "read(size: int) -> bytes. read at most size bytes, returned as bytes.\n"
764 "\n"
765 "Only makes one system call, so less data may be returned than requested\n"
766 "In non-blocking mode, returns None if no data is available.\n"
767 "On end-of-file, returns ''.");
769 PyDoc_STRVAR(readall_doc,
770 "readall() -> bytes. read all data from the file, returned as bytes.\n"
771 "\n"
772 "In non-blocking mode, returns as much as is immediately available,\n"
773 "or None if no data is available. On end-of-file, returns ''.");
775 PyDoc_STRVAR(write_doc,
776 "write(b: bytes) -> int. Write bytes b to file, return number written.\n"
777 "\n"
778 "Only makes one system call, so not all of the data may be written.\n"
779 "The number of bytes actually written is returned.");
781 PyDoc_STRVAR(fileno_doc,
782 "fileno() -> int. \"file descriptor\".\n"
783 "\n"
784 "This is needed for lower-level file interfaces, such the fcntl module.");
786 PyDoc_STRVAR(seek_doc,
787 "seek(offset: int[, whence: int]) -> None. Move to new file position.\n"
788 "\n"
789 "Argument offset is a byte count. Optional argument whence defaults to\n"
790 "0 (offset from start of file, offset should be >= 0); other values are 1\n"
791 "(move relative to current position, positive or negative), and 2 (move\n"
792 "relative to end of file, usually negative, although many platforms allow\n"
793 "seeking beyond the end of a file)."
794 "\n"
795 "Note that not all file objects are seekable.");
797 #ifdef HAVE_FTRUNCATE
798 PyDoc_STRVAR(truncate_doc,
799 "truncate([size: int]) -> None. Truncate the file to at most size bytes.\n"
800 "\n"
801 "Size defaults to the current file position, as returned by tell()."
802 "The current file position is changed to the value of size.");
803 #endif
805 PyDoc_STRVAR(tell_doc,
806 "tell() -> int. Current file position");
808 PyDoc_STRVAR(readinto_doc,
809 "readinto() -> Undocumented. Don't use this; it may go away.");
811 PyDoc_STRVAR(close_doc,
812 "close() -> None. Close the file.\n"
813 "\n"
814 "A closed file cannot be used for further I/O operations. close() may be\n"
815 "called more than once without error. Changes the fileno to -1.");
817 PyDoc_STRVAR(isatty_doc,
818 "isatty() -> bool. True if the file is connected to a tty device.");
820 PyDoc_STRVAR(seekable_doc,
821 "seekable() -> bool. True if file supports random-access.");
823 PyDoc_STRVAR(readable_doc,
824 "readable() -> bool. True if file was opened in a read mode.");
826 PyDoc_STRVAR(writable_doc,
827 "writable() -> bool. True if file was opened in a write mode.");
829 static PyMethodDef fileio_methods[] = {
830 {"read", (PyCFunction)fileio_read, METH_VARARGS, read_doc},
831 {"readall", (PyCFunction)fileio_readall, METH_NOARGS, readall_doc},
832 {"readinto", (PyCFunction)fileio_readinto, METH_VARARGS, readinto_doc},
833 {"write", (PyCFunction)fileio_write, METH_VARARGS, write_doc},
834 {"seek", (PyCFunction)fileio_seek, METH_VARARGS, seek_doc},
835 {"tell", (PyCFunction)fileio_tell, METH_VARARGS, tell_doc},
836 #ifdef HAVE_FTRUNCATE
837 {"truncate", (PyCFunction)fileio_truncate, METH_VARARGS, truncate_doc},
838 #endif
839 {"close", (PyCFunction)fileio_close, METH_NOARGS, close_doc},
840 {"seekable", (PyCFunction)fileio_seekable, METH_NOARGS, seekable_doc},
841 {"readable", (PyCFunction)fileio_readable, METH_NOARGS, readable_doc},
842 {"writable", (PyCFunction)fileio_writable, METH_NOARGS, writable_doc},
843 {"fileno", (PyCFunction)fileio_fileno, METH_NOARGS, fileno_doc},
844 {"isatty", (PyCFunction)fileio_isatty, METH_NOARGS, isatty_doc},
845 {NULL, NULL} /* sentinel */
848 /* 'closed' and 'mode' are attributes for backwards compatibility reasons. */
850 static PyObject *
851 get_closed(PyFileIOObject *self, void *closure)
853 return PyBool_FromLong((long)(self->fd < 0));
856 static PyObject *
857 get_closefd(PyFileIOObject *self, void *closure)
859 return PyBool_FromLong((long)(self->closefd));
862 static PyObject *
863 get_mode(PyFileIOObject *self, void *closure)
865 return PyString_FromString(mode_string(self));
868 static PyGetSetDef fileio_getsetlist[] = {
869 {"closed", (getter)get_closed, NULL, "True if the file is closed"},
870 {"closefd", (getter)get_closefd, NULL,
871 "True if the file descriptor will be closed"},
872 {"mode", (getter)get_mode, NULL, "String giving the file mode"},
873 {0},
876 PyTypeObject PyFileIO_Type = {
877 PyVarObject_HEAD_INIT(NULL, 0)
878 "_FileIO",
879 sizeof(PyFileIOObject),
881 (destructor)fileio_dealloc, /* tp_dealloc */
882 0, /* tp_print */
883 0, /* tp_getattr */
884 0, /* tp_setattr */
885 0, /* tp_compare */
886 (reprfunc)fileio_repr, /* tp_repr */
887 0, /* tp_as_number */
888 0, /* tp_as_sequence */
889 0, /* tp_as_mapping */
890 0, /* tp_hash */
891 0, /* tp_call */
892 0, /* tp_str */
893 PyObject_GenericGetAttr, /* tp_getattro */
894 0, /* tp_setattro */
895 0, /* tp_as_buffer */
896 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
897 fileio_doc, /* tp_doc */
898 0, /* tp_traverse */
899 0, /* tp_clear */
900 0, /* tp_richcompare */
901 offsetof(PyFileIOObject, weakreflist), /* tp_weaklistoffset */
902 0, /* tp_iter */
903 0, /* tp_iternext */
904 fileio_methods, /* tp_methods */
905 0, /* tp_members */
906 fileio_getsetlist, /* tp_getset */
907 0, /* tp_base */
908 0, /* tp_dict */
909 0, /* tp_descr_get */
910 0, /* tp_descr_set */
911 0, /* tp_dictoffset */
912 fileio_init, /* tp_init */
913 PyType_GenericAlloc, /* tp_alloc */
914 fileio_new, /* tp_new */
915 PyObject_Del, /* tp_free */
918 static PyMethodDef module_methods[] = {
919 {NULL, NULL}
922 PyMODINIT_FUNC
923 init_fileio(void)
925 PyObject *m; /* a module object */
927 m = Py_InitModule3("_fileio", module_methods,
928 "Fast implementation of io.FileIO.");
929 if (m == NULL)
930 return;
931 if (PyType_Ready(&PyFileIO_Type) < 0)
932 return;
933 Py_INCREF(&PyFileIO_Type);
934 PyModule_AddObject(m, "_FileIO", (PyObject *) &PyFileIO_Type);