[Python-checkins] r67131 - in sandbox/trunk/io-c: _bufferedio.c _fileio.c _iobase.c _iomodule.h build.py io.c
amaury.forgeotdarc
python-checkins at python.org
Fri Nov 7 01:26:37 CET 2008
Author: amaury.forgeotdarc
Date: Fri Nov 7 01:26:36 2008
New Revision: 67131
Log:
Split the module into more manageable pieces.
Added:
sandbox/trunk/io-c/_bufferedio.c (contents, props changed)
sandbox/trunk/io-c/_iobase.c (contents, props changed)
sandbox/trunk/io-c/_iomodule.h (contents, props changed)
Modified:
sandbox/trunk/io-c/_fileio.c
sandbox/trunk/io-c/build.py
sandbox/trunk/io-c/io.c
Added: sandbox/trunk/io-c/_bufferedio.c
==============================================================================
--- (empty file)
+++ sandbox/trunk/io-c/_bufferedio.c Fri Nov 7 01:26:36 2008
@@ -0,0 +1,1637 @@
+#include "Python.h"
+#include "structmember.h"
+#include "pythread.h"
+#include "_iomodule.h"
+
+/*
+ * BufferedIOBase class, inherits from IOBase.
+ */
+PyDoc_STRVAR(BufferedIOBase_doc,
+ "Base class for buffered IO objects.\n"
+ "\n"
+ "The main difference with RawIOBase is that the read() method\n"
+ "supports omitting the size argument, and does not have a default\n"
+ "implementation that defers to readinto().\n"
+ "\n"
+ "In addition, read(), readinto() and write() may raise\n"
+ "BlockingIOError if the underlying raw stream is in non-blocking\n"
+ "mode and not ready; unlike their raw counterparts, they will never\n"
+ "return None.\n"
+ "\n"
+ "A typical implementation should not inherit from a RawIOBase\n"
+ "implementation, but wrap one.\n"
+ );
+
+static PyObject *
+BufferedIOBase_readinto(PyObject *self, PyObject *args)
+{
+ Py_buffer buf;
+ Py_ssize_t len;
+ PyObject *data;
+
+ if (!PyArg_ParseTuple(args, "w*:readinto", &buf)) {
+ return NULL;
+ }
+
+ data = PyObject_CallMethod(self, "read", "n", buf.len);
+ if (data == NULL)
+ goto error;
+
+ if (!PyBytes_Check(data)) {
+ Py_DECREF(data);
+ PyErr_SetString(PyExc_TypeError, "read() should return bytes");
+ goto error;
+ }
+
+ len = Py_SIZE(data);
+ memcpy(buf.buf, PyBytes_AS_STRING(data), len);
+
+ PyBuffer_Release(&buf);
+ Py_DECREF(data);
+
+ return PyLong_FromSsize_t(len);
+
+ error:
+ PyBuffer_Release(&buf);
+ return NULL;
+}
+
+static PyMethodDef BufferedIOBase_methods[] = {
+ {"readinto", BufferedIOBase_readinto, METH_VARARGS},
+ {NULL, NULL}
+};
+
+PyTypeObject PyBufferedIOBase_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "BufferedIOBase", /*tp_name*/
+ 0, /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare */
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ BufferedIOBase_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BufferedIOBase_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PyIOBase_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+
+typedef struct {
+ PyObject_HEAD
+
+ PyObject *raw;
+
+ PyObject *name;
+ PyObject *mode;
+
+ PyObject *read_buf;
+ Py_ssize_t read_pos;
+ PyThread_type_lock read_lock;
+
+ PyObject *write_buf;
+ PyThread_type_lock write_lock;
+
+ Py_ssize_t buffer_size;
+ Py_ssize_t max_buffer_size;
+
+ PyObject *dict;
+ PyObject *weakreflist;
+} BufferedObject;
+
+static void
+BufferedObject_dealloc(BufferedObject *self)
+{
+ if (self->weakreflist != NULL)
+ PyObject_ClearWeakRefs((PyObject *)self);
+ Py_CLEAR(self->raw);
+ Py_CLEAR(self->name);
+ Py_CLEAR(self->mode);
+ Py_CLEAR(self->read_buf);
+ Py_CLEAR(self->write_buf);
+ Py_CLEAR(self->dict);
+}
+
+
+/*
+ * _BufferedIOMixin methods
+ * This is not a class, just a collection of methods that will be reused
+ * by BufferedReader and BufferedWriter
+ */
+
+/* Positioning */
+
+static PyObject*
+BufferedIOMixin_truncate(BufferedObject *self, PyObject *args)
+{
+ PyObject *pos = Py_None;
+ PyObject *res;
+
+ if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
+ return NULL;
+ }
+
+ /* Flush the stream. We're mixing buffered I/O with lower-level I/O,
+ * and a flush may be necessary to synch both views of the current
+ * file state.
+ */
+ res = PyObject_CallMethod(self->raw, "flush", NULL);
+ if (res == NULL)
+ return NULL;
+ Py_DECREF(res);
+
+ if (pos == Py_None)
+ pos = PyObject_CallMethod(self->raw, "tell", NULL);
+ else
+ Py_INCREF(pos);
+
+ /* XXX: Should seek() be used, instead of passing the position
+ * XXX directly to truncate?
+ */
+ res = PyObject_CallMethod(self->raw, "truncate", "O", pos);
+ Py_DECREF(pos);
+
+ return res;
+}
+
+/* Flush and close */
+
+static PyObject*
+BufferedIOMixin_flush(BufferedObject *self, PyObject *args)
+{
+ return PyObject_CallMethod(self->raw, "flush", NULL);
+}
+
+static int
+BufferedIOMixin_closed(BufferedObject *self)
+{
+ int closed;
+ PyObject *res = PyObject_GetAttrString(self->raw, "closed");
+ if (res == NULL)
+ return 0;
+ closed = PyObject_IsTrue(res);
+ Py_DECREF(res);
+ return closed;
+}
+
+static PyObject *
+BufferedIOMixin_closed_get(BufferedObject *self, void *context)
+{
+ return PyObject_GetAttrString(self->raw, "closed");
+}
+
+
+static PyObject*
+BufferedIOMixin_close(BufferedObject *self, PyObject *args)
+{
+ PyObject *res;
+
+ if (BufferedIOMixin_closed(self))
+ Py_RETURN_NONE;
+
+ res = PyObject_CallMethod((PyObject *)self, "flush", NULL);
+ if (res == NULL) {
+ /* If flush() fails, just give up */
+ if (PyErr_ExceptionMatches(PyExc_IOError))
+ PyErr_Clear();
+ else
+ return NULL;
+ }
+
+ return PyObject_CallMethod(self->raw, "close", NULL);
+}
+
+/* Inquiries */
+
+static PyObject*
+BufferedIOMixin_seekable(BufferedObject *self, PyObject *args)
+{
+ return PyObject_CallMethod(self->raw, "seekable", NULL);
+}
+
+static PyObject*
+BufferedIOMixin_readable(BufferedObject *self, PyObject *args)
+{
+ return PyObject_CallMethod(self->raw, "readable", NULL);
+}
+
+static PyObject*
+BufferedIOMixin_writable(BufferedObject *self, PyObject *args)
+{
+ return PyObject_CallMethod(self->raw, "writable", NULL);
+}
+
+/* Lower-level APIs */
+
+static PyObject*
+BufferedIOMixin_fileno(BufferedObject *self, PyObject *args)
+{
+ return PyObject_CallMethod(self->raw, "fileno", NULL);
+}
+
+static PyObject*
+BufferedIOMixin_isatty(BufferedObject *self, PyObject *args)
+{
+ return PyObject_CallMethod(self->raw, "isatty", NULL);
+}
+
+
+/*
+ * class BufferedReader
+ */
+
+PyDoc_STRVAR(BufferedReader_doc,
+ "Create a new buffered reader using the given readable raw IO object.");
+
+static int _BufferedReader_reset_read_buf(BufferedObject *self)
+{
+ PyObject *oldbuf = self->read_buf;
+
+ self->read_buf = PyBytes_FromStringAndSize(NULL, 0);
+ self->read_pos = 0;
+
+ Py_XDECREF(oldbuf);
+
+ if (self->read_buf == NULL)
+ return -1;
+
+ return 0;
+}
+
+static int
+BufferedReader_init(BufferedObject *self, PyObject *args, PyObject *kwds)
+{
+ char *kwlist[] = {"raw", "buffer_size", NULL};
+ Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
+ PyObject *raw;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedReader", kwlist,
+ &raw, &buffer_size)) {
+ return -1;
+ }
+
+ if (_PyIOBase_checkReadable(raw, NULL) == NULL)
+ return -1;
+
+ Py_INCREF(raw);
+ self->raw = raw;
+
+ self->buffer_size = buffer_size;
+ self->read_buf = NULL;
+
+ if( _BufferedReader_reset_read_buf(self) < 0)
+ return -1;
+
+ self->read_lock = PyThread_allocate_lock();
+ if (self->read_lock == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "can't allocate read lock");
+ return -1;
+ }
+
+ return 0;
+}
+
+static PyObject *
+_BufferedReader_read_unlocked(BufferedObject *self, Py_ssize_t n)
+{
+ PyObject *nodata_val = NULL;
+ PyObject *empty_values = NULL;
+
+ PyObject *buf = self->read_buf;
+ Py_ssize_t pos = self->read_pos;
+ PyObject *data, *chunks, *sep, *res;
+ Py_ssize_t current_size;
+
+ /* Special case for when the number of bytes to read is unspecified. */
+ if (n == -1) {
+ chunks = PyList_New(0);
+ if (chunks == NULL)
+ return NULL;
+
+ Py_INCREF(buf);
+ if (_BufferedReader_reset_read_buf(self) < 0)
+ return NULL;
+
+ /* Strip the consumed bytes */
+ current_size = Py_SIZE(buf) - pos;
+ data = NULL;
+ if (current_size) {
+ data = PyBytes_FromStringAndSize(PyBytes_AS_STRING(buf) + pos, current_size);
+ if (data == NULL) {
+ Py_DECREF(buf);
+ Py_DECREF(chunks);
+ return NULL;
+ }
+ Py_DECREF(buf);
+ }
+
+ while (1) {
+ if (data) {
+ if (PyList_Append(chunks, data) < 0) {
+ Py_DECREF(data);
+ Py_DECREF(chunks);
+ return NULL;
+ }
+ Py_DECREF(data);
+ }
+
+ /* Read until EOF or until read() would block. */
+ data = PyObject_CallMethod(self->raw, "read", NULL);
+
+ if (data == NULL) {
+ Py_DECREF(chunks);
+ return NULL;
+ }
+
+ if (data != Py_None && !PyBytes_Check(data)) {
+ Py_DECREF(data);
+ Py_DECREF(chunks);
+ PyErr_SetString(PyExc_TypeError, "read() should return bytes");
+ return NULL;
+ }
+
+ if (data == Py_None || Py_SIZE(data) == 0) {
+ if (current_size == 0) {
+ Py_DECREF(chunks);
+ return data;
+ }
+ else {
+ Py_DECREF(data);
+ sep = PyBytes_FromStringAndSize(NULL, 0);
+
+ if (sep == NULL) {
+ Py_DECREF(chunks);
+ return NULL;
+ }
+ res =_PyBytes_Join(sep, chunks);
+ Py_DECREF(sep);
+ Py_DECREF(chunks);
+
+ return res;
+ }
+ }
+
+ current_size += Py_SIZE(data);
+ }
+ }
+
+ /* The number of bytes to read is specified, return at most n bytes. */
+
+ current_size = Py_SIZE(buf) - pos; /* Length of the available buffered data. */
+ if (n <= current_size) {
+ /* Fast path: the data to read is fully buffered. */
+ self->read_pos += n;
+ return PyBytes_FromStringAndSize(PyBytes_AS_STRING(buf) + pos, n);
+ }
+
+ /* Slow path: read from the stream until enough bytes are read,
+ * or until an EOF occurs or until read() would block.
+ */
+ chunks = PyList_New(0);
+ if (chunks == NULL)
+ return NULL;
+
+ data = NULL;
+
+ if (current_size)
+ data = PyBytes_FromStringAndSize(PyBytes_AS_STRING(buf) + pos, current_size);
+
+ while (1) {
+ Py_ssize_t wanted;
+
+ if (data) {
+ if (PyList_Append(chunks, data) < 0) {
+ Py_DECREF(data);
+ Py_DECREF(chunks);
+ return NULL;
+ }
+ Py_DECREF(data);
+ }
+
+ if (current_size >= n)
+ break;
+
+ wanted = n;
+ if (wanted < self->buffer_size)
+ wanted = self->buffer_size;
+
+ data = PyObject_CallMethod(self->raw, "read", "n", wanted);
+
+ if (data != Py_None && !PyBytes_Check(data)) {
+ Py_DECREF(data);
+ Py_DECREF(chunks);
+ PyErr_SetString(PyExc_TypeError, "read() should return bytes");
+ return NULL;
+ }
+
+ if (data == Py_None || Py_SIZE(data) == 0) {
+ /* EOF occurred or read() would block. */
+
+ if (current_size == 0) {
+ Py_DECREF(chunks);
+
+ if( _BufferedReader_reset_read_buf(self) < 0) {
+ Py_DECREF(data);
+ return NULL;
+ }
+
+ return data;
+ }
+ else {
+ Py_DECREF(data);
+ break;
+ }
+ }
+
+ current_size += Py_SIZE(data);
+ }
+
+ sep = PyBytes_FromStringAndSize(NULL, 0);
+
+ if (sep == NULL) {
+ Py_DECREF(chunks);
+ return NULL;
+ }
+
+ res =_PyBytes_Join(sep, chunks);
+ Py_DECREF(sep);
+ Py_DECREF(chunks);
+
+ if (Py_SIZE(res) > n) {
+ /* Save the extra data in the buffer. */
+ self->read_pos = 0;
+ buf = self->read_buf;
+ self->read_buf = PyBytes_FromStringAndSize(PyBytes_AS_STRING(res) + n, Py_SIZE(res) - n);
+ Py_DECREF(buf);
+ if (self->read_buf == NULL) {
+ Py_DECREF(res);
+ return NULL;
+ }
+
+ /* Truncate the result to the desired length */
+ buf = PyBytes_FromStringAndSize(PyBytes_AS_STRING(res), n);
+ if (buf == NULL) {
+ Py_DECREF(res);
+ return NULL;
+ }
+
+ Py_DECREF(res);
+ res = buf;
+ }
+
+ return res;
+}
+
+static PyObject *
+BufferedReader_read(BufferedObject *self, PyObject *args)
+{
+ Py_ssize_t n = -1;
+ PyObject *res;
+
+ if (!PyArg_ParseTuple(args, "|n:read", &n)) {
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ PyThread_acquire_lock(self->read_lock, 1);
+ Py_END_ALLOW_THREADS
+
+ res = _BufferedReader_read_unlocked(self, n);
+
+ PyThread_release_lock(self->read_lock);
+
+ return res;
+}
+
+static PyObject *
+_BufferedReader_peek_unlocked(BufferedObject *self, Py_ssize_t n)
+{
+ Py_ssize_t have;
+
+ if (n > self->buffer_size)
+ n = self->buffer_size;
+
+ have = Py_SIZE(self->read_buf) - self->read_pos;
+
+ if (have < n) {
+ Py_ssize_t to_read = self->buffer_size - have;
+ PyObject *current = PyObject_CallMethod(self->raw, "read", "n", to_read);
+
+ if (current == NULL)
+ return NULL;
+
+ if (!PyBytes_Check(current)) {
+ Py_DECREF(current);
+ PyErr_SetString(PyExc_TypeError, "read() should return bytes");
+ return NULL;
+ }
+
+ if (Py_SIZE(current) > 0) {
+ PyObject *oldbuf = self->read_buf;
+ self->read_buf = PyBytes_FromStringAndSize(NULL, have + Py_SIZE(current));
+ memcpy(PyBytes_AS_STRING(self->read_buf), PyBytes_AS_STRING(oldbuf) + self->read_pos, have);
+ memcpy(PyBytes_AS_STRING(self->read_buf) + have, PyBytes_AS_STRING(current), Py_SIZE(current));
+ self->read_pos = 0;
+ }
+ Py_DECREF(current);
+ }
+
+ if (self->read_pos == 0) {
+ Py_INCREF(self->read_buf);
+ return self->read_buf;
+ }
+ else {
+ return PyBytes_FromStringAndSize(
+ PyBytes_AS_STRING(self->read_buf) + self->read_pos,
+ Py_SIZE(self->read_buf) - self->read_pos);
+ }
+}
+
+static PyObject *
+BufferedReader_peek(BufferedObject *self, PyObject *args)
+{
+ Py_ssize_t n = 0;
+ PyObject *res;
+
+ if (!PyArg_ParseTuple(args, "|n:peek", &n)) {
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ PyThread_acquire_lock(self->read_lock, 1);
+ Py_END_ALLOW_THREADS
+
+ res = _BufferedReader_peek_unlocked(self, n);
+
+ PyThread_release_lock(self->read_lock);
+
+ return res;
+}
+
+static PyObject *
+BufferedReader_read1(BufferedObject *self, PyObject *args)
+{
+ Py_ssize_t n, have;
+ PyObject *res;
+
+ if (!PyArg_ParseTuple(args, "n:read1", &n)) {
+ return NULL;
+ }
+
+ if (n <= 0)
+ return PyBytes_FromStringAndSize(NULL, 0);
+
+ Py_BEGIN_ALLOW_THREADS
+ PyThread_acquire_lock(self->read_lock, 1);
+ Py_END_ALLOW_THREADS
+
+ res = _BufferedReader_peek_unlocked(self, 1);
+ if(res == NULL)
+ goto end;
+ Py_DECREF(res);
+
+ have = Py_SIZE(self->read_buf) - self->read_pos;
+ if (n > have)
+ n = have;
+
+ res = _BufferedReader_read_unlocked(self, n);
+
+ end:
+ PyThread_release_lock(self->read_lock);
+
+ return res;
+}
+
+static PyObject*
+BufferedReader_seek(BufferedObject *self, PyObject *args)
+{
+ Py_ssize_t pos;
+ int whence = 0;
+ PyObject *res;
+
+ if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &whence)) {
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ PyThread_acquire_lock(self->read_lock, 1);
+ Py_END_ALLOW_THREADS
+
+ if (whence == 1) {
+ pos -= Py_SIZE(self->read_buf) - self->read_pos;
+ }
+
+ res = PyObject_CallMethod(self->raw, "seek", "ni", pos, whence);
+ if (res == NULL)
+ return NULL;
+
+ if (_BufferedReader_reset_read_buf(self) < 0)
+ Py_CLEAR(res);
+
+ PyThread_release_lock(self->read_lock);
+
+ return res;
+}
+
+static PyObject*
+BufferedReader_tell(BufferedObject *self, PyObject *args)
+{
+ PyObject *op1, *op2, *res;
+
+ op1 = PyObject_CallMethod(self->raw, "tell", NULL);
+
+ if (op1 == NULL)
+ return NULL;
+
+ op2 = PyLong_FromSsize_t(Py_SIZE(self->read_buf) - self->read_pos);
+ if (op2 == NULL) {
+ Py_DECREF(op1);
+ return NULL;
+ }
+
+ res = PyNumber_Subtract(op1, op2);
+ Py_DECREF(op1);
+ Py_DECREF(op2);
+ return res;
+}
+
+static PyMethodDef BufferedReader_methods[] = {
+ /* BufferedIOMixin methods */
+ {"truncate", (PyCFunction)BufferedIOMixin_truncate, METH_VARARGS},
+ {"flush", (PyCFunction)BufferedIOMixin_flush, METH_NOARGS},
+ {"close", (PyCFunction)BufferedIOMixin_close, METH_NOARGS},
+ {"seekable", (PyCFunction)BufferedIOMixin_seekable, METH_NOARGS},
+ {"readable", (PyCFunction)BufferedIOMixin_readable, METH_NOARGS},
+ {"writable", (PyCFunction)BufferedIOMixin_writable, METH_NOARGS},
+ {"fileno", (PyCFunction)BufferedIOMixin_fileno, METH_NOARGS},
+ {"isatty", (PyCFunction)BufferedIOMixin_isatty, METH_NOARGS},
+
+ {"read", (PyCFunction)BufferedReader_read, METH_VARARGS},
+ {"peek", (PyCFunction)BufferedReader_peek, METH_VARARGS},
+ {"read1", (PyCFunction)BufferedReader_read1, METH_VARARGS},
+ {"seek", (PyCFunction)BufferedReader_seek, METH_VARARGS},
+ {"tell", (PyCFunction)BufferedReader_tell, METH_NOARGS},
+ {NULL, NULL}
+};
+
+static PyMemberDef BufferedReader_members[] = {
+ {"_name", T_OBJECT, offsetof(BufferedObject, name), 0},
+ {"_mode", T_OBJECT, offsetof(BufferedObject, mode), 0},
+ {NULL}
+};
+
+static PyGetSetDef BufferedReader_getset[] = {
+ {"closed", (getter)BufferedIOMixin_closed_get, NULL, NULL},
+ {0}
+};
+
+
+PyTypeObject PyBufferedReader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "BufferedReader", /*tp_name*/
+ sizeof(BufferedObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)BufferedObject_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare */
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ BufferedReader_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ offsetof(BufferedObject, weakreflist), /*tp_weaklistoffset*/
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BufferedReader_methods, /* tp_methods */
+ BufferedReader_members, /* tp_members */
+ BufferedReader_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ offsetof(BufferedObject, dict), /* tp_dictoffset */
+ (initproc)BufferedReader_init, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+
+/*
+ * class BufferedWriter
+ */
+PyDoc_STRVAR(BufferedWriter_doc,
+ "A buffer for a writeable sequential RawIO object.\n"
+ "\n"
+ "The constructor creates a BufferedWriter for the given writeable raw\n"
+ "stream. If the buffer_size is not given, it defaults to\n"
+ "DEAFULT_BUFFER_SIZE. If max_buffer_size is omitted, it defaults to\n"
+ "twice the buffer size.\n"
+ );
+
+static int
+BufferedWriter_init(BufferedObject *self, PyObject *args, PyObject *kwds)
+{
+ char *kwlist[] = {"raw", "buffer_size", "max_buffer_size", NULL};
+ Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
+ Py_ssize_t max_buffer_size = -1;
+ PyObject *raw;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|nn:BufferedReader", kwlist,
+ &raw, &buffer_size, &max_buffer_size)) {
+ return -1;
+ }
+
+ if (_PyIOBase_checkWritable(raw, NULL) == NULL)
+ return -1;
+
+ Py_INCREF(raw);
+ self->raw = raw;
+
+ if (max_buffer_size < 0)
+ max_buffer_size = buffer_size * 2;
+ self->buffer_size = buffer_size;
+ self->max_buffer_size = max_buffer_size;
+
+ self->write_buf = PyByteArray_FromStringAndSize(NULL, 0);
+ if (self->write_buf == NULL)
+ return -1;
+
+ self->write_lock = PyThread_allocate_lock();
+ if (self->write_lock == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "can't allocate write lock");
+ return -1;
+ }
+
+ return 0;
+}
+
+static PyObject *
+_BufferedWriter_flush_unlocked(BufferedObject *self)
+{
+ Py_ssize_t written = 0;
+
+ if (BufferedIOMixin_closed(self)) {
+ PyErr_SetString(PyExc_ValueError, "flush of closed file");
+ return NULL;
+ }
+
+ while (Py_SIZE(self->write_buf) > 0) {
+ PyObject *slice, *res;
+ Py_ssize_t w;
+ PyObject *n = PyObject_CallMethod(self->raw, "write", "O", self->write_buf);
+
+ if (n == NULL) {
+ PyObject *type, *value, *traceback;
+ PyErr_Fetch(&type, &value, &traceback);
+
+ if (value == NULL ||
+ !PyErr_GivenExceptionMatches(value, PyExc_BlockingIOError)) {
+ PyErr_Restore(type, value, traceback);
+ return NULL;
+ }
+
+ w = ((PyBlockingIOErrorObject *)value)->written;
+
+ /* del self->write_buf[:w] */
+ slice = _PySlice_FromIndices(0, w);
+ if (slice == NULL)
+ return NULL;
+ res = PyObject_CallMethod(self->write_buf, "__delitem__", "O", slice);
+ Py_DECREF(slice);
+ if (res == NULL)
+ return NULL;
+ Py_DECREF(res);
+
+ written += w;
+ ((PyBlockingIOErrorObject *)value)->written = written;
+
+ PyErr_Restore(type, value, traceback);
+ return NULL;
+ }
+
+ /* del self->write_buf[:w] */
+ w = PyNumber_AsSsize_t(n, PyExc_ValueError);
+ Py_DECREF(n);
+ if (w == -1 && PyErr_Occurred())
+ return NULL;
+
+ slice = _PySlice_FromIndices(0, w);
+ if (slice == NULL)
+ return NULL;
+ res = PyObject_CallMethod(self->write_buf, "__delitem__", "O", slice);
+ Py_DECREF(slice);
+ if (res == NULL)
+ return NULL;
+ Py_DECREF(res);
+
+ written += w;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+BufferedWriter_write(BufferedObject *self, PyObject *args)
+{
+ PyObject *res;
+ Py_buffer buf;
+ Py_ssize_t before, written;
+
+ if (!PyArg_ParseTuple(args, "y*:write", &buf)) {
+ return NULL;
+ }
+
+ if (BufferedIOMixin_closed(self)) {
+ PyErr_SetString(PyExc_ValueError, "write to closed file");
+ PyBuffer_Release(&buf);
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ PyThread_acquire_lock(self->write_lock, 1);
+ Py_END_ALLOW_THREADS
+
+ /* XXX we can implement some more tricks to try and avoid
+ * partial writes
+ */
+
+ if (Py_SIZE(self->write_buf) > self->buffer_size) {
+ /* We're full, so let's pre-flush the buffer*/
+ res = _BufferedWriter_flush_unlocked(self);
+ if (res == NULL) {
+ /* We can't accept anything else. */
+ PyObject *type, *value, *traceback;
+ PyErr_Fetch(&type, &value, &traceback);
+
+ if (value != NULL &&
+ PyErr_GivenExceptionMatches(value, PyExc_BlockingIOError)) {
+ ((PyBlockingIOErrorObject *)value)->written = 0;
+ }
+
+ PyErr_Restore(type, value, traceback);
+ goto fail;
+ }
+ }
+
+ written = buf.len;
+
+ before = Py_SIZE(self->write_buf);
+ if (PyByteArray_Resize(self->write_buf, before + written) < 0) {
+ res = NULL;
+ goto fail;
+ }
+ memcpy(PyByteArray_AS_STRING(self->write_buf) + before, buf.buf, written);
+
+ if (Py_SIZE(self->write_buf) > self->buffer_size) {
+ res = _BufferedWriter_flush_unlocked(self);
+ if (res == NULL) {
+ PyObject *type, *value, *traceback;
+ PyErr_Fetch(&type, &value, &traceback);
+
+ if (value != NULL &&
+ PyErr_GivenExceptionMatches(value, PyExc_BlockingIOError)) {
+
+ Py_ssize_t overage =
+ Py_SIZE(self->write_buf) - self->max_buffer_size;
+
+ if (overage > 0) {
+ /* We've hit max_buffer_size. We have to accept a
+ * partial write and cut back our buffer.
+ */
+ if (PyByteArray_Resize(self->write_buf, self->max_buffer_size) < 0)
+ goto fail;
+ ((PyBlockingIOErrorObject *)value)->written = overage;
+ }
+ else
+ {
+ Py_CLEAR(type);
+ Py_CLEAR(value);
+ Py_CLEAR(traceback);
+ goto end;
+ }
+ }
+
+ PyErr_Restore(type, value, traceback);
+ goto fail;
+ }
+ }
+
+ end:
+ res = PyLong_FromSsize_t(written);
+
+ fail:
+ PyThread_release_lock(self->write_lock);
+ PyBuffer_Release(&buf);
+ return res;
+}
+
+static PyObject *
+BufferedWriter_truncate(BufferedObject *self, PyObject *args)
+{
+ PyObject *pos = Py_None;
+ PyObject *res;
+
+ if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ PyThread_acquire_lock(self->write_lock, 1);
+ Py_END_ALLOW_THREADS
+
+ res = _BufferedWriter_flush_unlocked(self);
+ if (res == NULL)
+ goto end;
+ Py_DECREF(res);
+
+ res = BufferedIOMixin_truncate(self, args);
+
+ end:
+ PyThread_release_lock(self->write_lock);
+ return res;
+}
+
+static PyObject *
+BufferedWriter_flush(BufferedObject *self, PyObject *args)
+{
+ PyObject *res;
+
+ Py_BEGIN_ALLOW_THREADS
+ PyThread_acquire_lock(self->write_lock, 1);
+ Py_END_ALLOW_THREADS
+
+ res = _BufferedWriter_flush_unlocked(self);
+
+ PyThread_release_lock(self->write_lock);
+
+ return res;
+}
+
+static PyObject *
+BufferedWriter_tell(BufferedObject *self, PyObject *args)
+{
+ PyObject *op1, *op2, *res;
+
+ op1 = PyObject_CallMethod(self->raw, "tell", NULL);
+
+ op2 = PyLong_FromSsize_t(Py_SIZE(self->write_buf));
+ if (op2 == NULL) {
+ Py_DECREF(op1);
+ return NULL;
+ }
+
+ res = PyNumber_Add(op1, op2);
+ Py_DECREF(op1);
+ Py_DECREF(op2);
+ return res;
+}
+
+static PyObject *
+BufferedWriter_seek(BufferedObject *self, PyObject *args)
+{
+ Py_ssize_t pos;
+ int whence = 0;
+ PyObject *res;
+
+ if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &whence)) {
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ PyThread_acquire_lock(self->write_lock, 1);
+ Py_END_ALLOW_THREADS
+
+ res = _BufferedWriter_flush_unlocked(self);
+ if (res == NULL)
+ goto end;
+
+ res = PyObject_CallMethod(self->raw, "seek", "ni", pos, whence);
+
+ end:
+ PyThread_release_lock(self->write_lock);
+ return res;
+}
+
+static PyMethodDef BufferedWriter_methods[] = {
+ /* BufferedIOMixin methods */
+ {"close", (PyCFunction)BufferedIOMixin_close, METH_NOARGS},
+ {"seekable", (PyCFunction)BufferedIOMixin_seekable, METH_NOARGS},
+ {"readable", (PyCFunction)BufferedIOMixin_readable, METH_NOARGS},
+ {"writable", (PyCFunction)BufferedIOMixin_writable, METH_NOARGS},
+ {"fileno", (PyCFunction)BufferedIOMixin_fileno, METH_NOARGS},
+ {"isatty", (PyCFunction)BufferedIOMixin_isatty, METH_NOARGS},
+
+ {"write", (PyCFunction)BufferedWriter_write, METH_VARARGS},
+ {"truncate", (PyCFunction)BufferedWriter_truncate, METH_VARARGS},
+ {"flush", (PyCFunction)BufferedWriter_flush, METH_NOARGS},
+ {"seek", (PyCFunction)BufferedWriter_seek, METH_VARARGS},
+ {"tell", (PyCFunction)BufferedWriter_tell, METH_NOARGS},
+ {NULL, NULL}
+};
+
+static PyMemberDef BufferedWriter_members[] = {
+ {"_name", T_OBJECT, offsetof(BufferedObject, name), 0},
+ {"_mode", T_OBJECT, offsetof(BufferedObject, mode), 0},
+ {NULL}
+};
+
+static PyGetSetDef BufferedWriter_getset[] = {
+ {"closed", (getter)BufferedIOMixin_closed_get, NULL, NULL},
+ {0}
+};
+
+
+PyTypeObject PyBufferedWriter_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "BufferedWriter", /*tp_name*/
+ sizeof(BufferedObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)BufferedObject_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare */
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ BufferedWriter_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ offsetof(BufferedObject, weakreflist), /*tp_weaklistoffset*/
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BufferedWriter_methods, /* tp_methods */
+ BufferedWriter_members, /* tp_members */
+ BufferedWriter_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ offsetof(BufferedObject, dict), /* tp_dictoffset */
+ (initproc)BufferedWriter_init, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+
+
+/*
+ * BufferedRWPair
+ */
+
+PyDoc_STRVAR(BufferedRWPair_doc,
+ "A buffered reader and writer object together.\n"
+ "\n"
+ "A buffered reader object and buffered writer object put together to\n"
+ "form a sequential IO object that can read and write. This is typically\n"
+ "used with a socket or two-way pipe.\n"
+ "\n"
+ "reader and writer are RawIOBase objects that are readable and\n"
+ "writeable respectively. If the buffer_size is omitted it defaults to\n"
+ "DEFAULT_BUFFER_SIZE. The max_buffer_size (for the buffered writer)\n"
+ "defaults to twice the buffer size.\n"
+ );
+
+/* XXX The usefulness of this (compared to having two separate IO objects) is
+ * questionable.
+ */
+
+typedef struct {
+ PyObject_HEAD
+ BufferedObject *reader;
+ BufferedObject *writer;
+} BufferedRWPairObject;
+
+static int
+BufferedRWPair_init(BufferedRWPairObject *self, PyObject *args,
+ PyObject *kwds)
+{
+ PyObject *reader, *writer;
+ Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
+ Py_ssize_t max_buffer_size = -1;
+
+ if (!PyArg_ParseTuple(args, "OO|nn:BufferedRWPair", &reader, &writer,
+ &buffer_size, &max_buffer_size)) {
+ return -1;
+ }
+
+ if (_PyIOBase_checkReadable(reader, NULL) == NULL)
+ return -1;
+ if (_PyIOBase_checkWritable(writer, NULL) == NULL)
+ return -1;
+
+ args = Py_BuildValue("(n)", buffer_size);
+ if (args == NULL) {
+ Py_CLEAR(self->reader);
+ return -1;
+ }
+ self->reader = (BufferedObject*)PyType_GenericNew(&PyBufferedReader_Type, args, NULL);
+ Py_DECREF(args);
+ if (self->reader == NULL)
+ return -1;
+
+ args = Py_BuildValue("(nn)", buffer_size, max_buffer_size);
+ if (args == NULL) {
+ Py_CLEAR(self->reader);
+ return -1;
+ }
+ self->writer = (BufferedObject*)PyType_GenericNew(&PyBufferedWriter_Type, args, NULL);
+ Py_DECREF(args);
+ if (self->writer == NULL) {
+ Py_CLEAR(self->reader);
+ return -1;
+ }
+ return 0;
+}
+
+static void
+BufferedRWPair_dealloc(BufferedRWPairObject *self)
+{
+ Py_CLEAR(self->reader);
+ Py_CLEAR(self->writer);
+}
+
+static PyObject *
+_forward_call(BufferedObject *self, const char* name, PyObject *args)
+{
+ PyObject *func = PyObject_GetAttrString((PyObject*)self, name);
+ PyObject *ret;
+
+ if (func == NULL) {
+ PyErr_SetString(PyExc_AttributeError, name);
+ return NULL;
+ }
+
+ ret = PyObject_CallObject(func, args);
+ Py_DECREF(func);
+ return ret;
+}
+
+static PyObject *
+BufferedRWPair_read(BufferedRWPairObject *self, PyObject *args)
+{
+ return _forward_call(self->reader, "read", args);
+}
+
+static PyObject *
+BufferedRWPair_peek(BufferedRWPairObject *self, PyObject *args)
+{
+ return _forward_call(self->reader, "peek", args);
+}
+
+static PyObject *
+BufferedRWPair_read1(BufferedRWPairObject *self, PyObject *args)
+{
+ return _forward_call(self->reader, "read1", args);
+}
+
+static PyObject *
+BufferedRWPair_write(BufferedRWPairObject *self, PyObject *args)
+{
+ return _forward_call(self->writer, "write", args);
+}
+
+static PyObject *
+BufferedRWPair_flush(BufferedRWPairObject *self, PyObject *args)
+{
+ return _forward_call(self->writer, "flush", args);
+}
+
+static PyObject *
+BufferedRWPair_readable(BufferedRWPairObject *self, PyObject *args)
+{
+ return _forward_call(self->reader, "readable", args);
+}
+
+static PyObject *
+BufferedRWPair_writable(BufferedRWPairObject *self, PyObject *args)
+{
+ return _forward_call(self->writer, "writable", args);
+}
+
+static PyObject *
+BufferedRWPair_close(BufferedRWPairObject *self, PyObject *args)
+{
+ PyObject *ret = _forward_call(self->writer, "close", args);
+ if (ret == NULL)
+ return NULL;
+ Py_DECREF(ret);
+
+ return _forward_call(self->reader, "close", args);
+}
+
+static PyObject *
+BufferedRWPair_isatty(BufferedRWPairObject *self, PyObject *args)
+{
+ PyObject *ret = _forward_call(self->writer, "isatty", args);
+
+ if (ret != Py_False) {
+ /* either True or exception */
+ return ret;
+ }
+ Py_DECREF(ret);
+
+ return _forward_call(self->reader, "isatty", args);
+}
+
+
+static PyMethodDef BufferedRWPair_methods[] = {
+ {"read", (PyCFunction)BufferedRWPair_read, METH_VARARGS},
+ {"peek", (PyCFunction)BufferedRWPair_peek, METH_VARARGS},
+ {"read1", (PyCFunction)BufferedRWPair_read1, METH_VARARGS},
+
+ {"write", (PyCFunction)BufferedRWPair_write, METH_VARARGS},
+ {"flush", (PyCFunction)BufferedRWPair_flush, METH_NOARGS},
+
+ {"readable", (PyCFunction)BufferedRWPair_readable, METH_NOARGS},
+ {"writable", (PyCFunction)BufferedRWPair_writable, METH_NOARGS},
+
+ {"close", (PyCFunction)BufferedRWPair_close, METH_NOARGS},
+ {"isatty", (PyCFunction)BufferedRWPair_isatty, METH_NOARGS},
+
+ {NULL, NULL}
+};
+
+PyTypeObject PyBufferedRWPair_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "BufferedRWPair", /*tp_name*/
+ sizeof(BufferedRWPairObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)BufferedRWPair_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare */
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ BufferedRWPair_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ offsetof(BufferedObject, weakreflist), /*tp_weaklistoffset*/
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BufferedRWPair_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ offsetof(BufferedObject, dict), /* tp_dictoffset */
+ (initproc)BufferedRWPair_init, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+
+
+/*
+ * BufferedRandom
+ */
+
+PyDoc_STRVAR(BufferedRandom_doc,
+ "A buffered interface to random access streams.\n"
+ "\n"
+ "The constructor creates a reader and writer for a seekable stream,\n"
+ "raw, given in the first argument. If the buffer_size is omitted it\n"
+ "defaults to DEFAULT_BUFFER_SIZE. The max_buffer_size (for the buffered\n"
+ "writer) defaults to twice the buffer size.\n"
+ );
+
+static int
+BufferedRandom_init(BufferedObject *self, PyObject *args, PyObject *kwds)
+{
+ char *kwlist[] = {"raw", "buffer_size", "max_buffer_size", NULL};
+ Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
+ Py_ssize_t max_buffer_size = -1;
+ PyObject *raw;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|nn:BufferedReader", kwlist,
+ &raw, &buffer_size, &max_buffer_size)) {
+ return -1;
+ }
+
+ if (_PyIOBase_checkSeekable(raw, NULL) == NULL)
+ return -1;
+ if (_PyIOBase_checkReadable(raw, NULL) == NULL)
+ return -1;
+ if (_PyIOBase_checkWritable(raw, NULL) == NULL)
+ return -1;
+
+ Py_INCREF(raw);
+ self->raw = raw;
+
+ if (max_buffer_size < 0)
+ max_buffer_size = buffer_size * 2;
+ self->buffer_size = buffer_size;
+ self->max_buffer_size = max_buffer_size;
+
+ if( _BufferedReader_reset_read_buf(self) < 0)
+ return -1;
+
+ self->read_lock = PyThread_allocate_lock();
+ if (self->read_lock == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "can't allocate read lock");
+ return -1;
+ }
+
+ self->write_buf = PyByteArray_FromStringAndSize(NULL, 0);
+ if (self->write_buf == NULL)
+ return -1;
+
+ self->write_lock = PyThread_allocate_lock();
+ if (self->write_lock == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "can't allocate write lock");
+ return -1;
+ }
+
+ return 0;
+}
+
+static PyObject *
+BufferedRandom_tell(BufferedObject *self, PyObject *args)
+{
+ if (Py_SIZE(self->write_buf))
+ return BufferedWriter_tell(self, args);
+ else
+ return BufferedReader_tell(self, args);
+}
+
+static PyObject *
+BufferedRandom_seek(BufferedObject *self, PyObject *args)
+{
+ Py_ssize_t pos;
+ int whence = 0;
+ PyObject *res;
+
+ if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &whence)) {
+ return NULL;
+ }
+
+ res = PyObject_CallMethod((PyObject*)self, "flush", NULL);
+ if (res == NULL)
+ return NULL;
+
+ /* First do the raw seek, then empty the read buffer, so that
+ * if the raw seek fails, we don't lose buffered data forever.
+ */
+
+ res = PyObject_CallMethod(self->raw, "seek", "ni", pos, whence);
+ if (res == NULL)
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ PyThread_acquire_lock(self->read_lock, 1);
+ Py_END_ALLOW_THREADS
+
+ if( _BufferedReader_reset_read_buf(self) < 0)
+ Py_CLEAR(res);
+
+ PyThread_release_lock(self->read_lock);
+ return res;
+}
+
+static PyObject *
+BufferedRandom_truncate(BufferedObject *self, PyObject *args)
+{
+ PyObject *pos = Py_None;
+ PyObject *res;
+
+ if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
+ return NULL;
+ }
+
+ if (pos == Py_None)
+ pos = PyObject_CallMethod(self->raw, "tell", NULL);
+ else
+ Py_INCREF(pos);
+
+ /* Use seek to flush the read buffer. */
+ res = PyObject_CallMethod((PyObject *)self, "seek", "O", pos);
+ Py_DECREF(pos);
+ if (res == NULL)
+ return NULL;
+ Py_DECREF(res);
+
+ args = PyTuple_New(0);
+ if (args == NULL)
+ return NULL;
+ res = BufferedWriter_truncate(self, args);
+ Py_DECREF(args);
+
+ return res;
+}
+
+static PyObject *
+BufferedRandom_read(BufferedObject *self, PyObject *args)
+{
+ Py_ssize_t n = -1;
+ PyObject *res;
+
+ if (!PyArg_ParseTuple(args, "|n:read", &n)) {
+ return NULL;
+ }
+
+ res = BufferedWriter_flush(self, Py_None);
+ if (res == NULL)
+ return NULL;
+
+ return BufferedReader_read(self, args);
+}
+
+static PyObject *
+BufferedRandom_readinto(BufferedObject *self, PyObject *args)
+{
+ PyObject *res;
+
+ res = BufferedWriter_flush(self, Py_None);
+ if (res == NULL)
+ return NULL;
+ Py_DECREF(res);
+
+ return BufferedIOBase_readinto((PyObject *)self, args);
+}
+
+static PyObject *
+BufferedRandom_peek(BufferedObject *self, PyObject *args)
+{
+ PyObject *res = BufferedWriter_flush(self, Py_None);
+ if (res == NULL)
+ return NULL;
+ Py_DECREF(res);
+
+ return BufferedReader_peek(self, args);
+}
+
+static PyObject *
+BufferedRandom_read1(BufferedObject *self, PyObject *args)
+{
+ PyObject *res = BufferedWriter_flush(self, Py_None);
+ if (res == NULL)
+ return NULL;
+ Py_DECREF(res);
+
+ return BufferedReader_read1(self, args);
+}
+
+static PyObject *
+BufferedRandom_write(BufferedObject *self, PyObject *args)
+{
+ if (Py_SIZE(self->read_buf) > 0) {
+ PyObject *res;
+ /* Undo readahead */
+
+ Py_BEGIN_ALLOW_THREADS
+ PyThread_acquire_lock(self->read_lock, 1);
+ Py_END_ALLOW_THREADS
+
+ res = PyObject_CallMethod(self->raw, "seek", "ni",
+ self->read_pos - Py_SIZE(self->read_buf), 1);
+ Py_XDECREF(res);
+ if (res != NULL) {
+ if( _BufferedReader_reset_read_buf(self) < 0)
+ res = NULL;
+ }
+
+ PyThread_release_lock(self->read_lock);
+
+ if (res == NULL)
+ return NULL;
+ }
+
+ return BufferedWriter_write(self, args);
+}
+
+
+static PyMethodDef BufferedRandom_methods[] = {
+ /* BufferedIOMixin methods */
+ {"close", (PyCFunction)BufferedIOMixin_close, METH_NOARGS},
+ {"seekable", (PyCFunction)BufferedIOMixin_seekable, METH_NOARGS},
+ {"readable", (PyCFunction)BufferedIOMixin_readable, METH_NOARGS},
+ {"writable", (PyCFunction)BufferedIOMixin_writable, METH_NOARGS},
+ {"fileno", (PyCFunction)BufferedIOMixin_fileno, METH_NOARGS},
+ {"isatty", (PyCFunction)BufferedIOMixin_isatty, METH_NOARGS},
+
+ {"flush", (PyCFunction)BufferedWriter_flush, METH_NOARGS},
+
+ {"seek", (PyCFunction)BufferedRandom_seek, METH_VARARGS},
+ {"tell", (PyCFunction)BufferedRandom_tell, METH_NOARGS},
+ {"truncate", (PyCFunction)BufferedRandom_truncate, METH_VARARGS},
+ {"read", (PyCFunction)BufferedRandom_read, METH_VARARGS},
+ {"readinto", (PyCFunction)BufferedRandom_readinto, METH_VARARGS},
+ {"peek", (PyCFunction)BufferedRandom_peek, METH_VARARGS},
+ {"read1", (PyCFunction)BufferedRandom_read1, METH_VARARGS},
+ {"write", (PyCFunction)BufferedRandom_write, METH_VARARGS},
+ {NULL, NULL}
+};
+
+static PyMemberDef BufferedRandom_members[] = {
+ {"_name", T_OBJECT, offsetof(BufferedObject, name), 0},
+ {"_mode", T_OBJECT, offsetof(BufferedObject, mode), 0},
+ {NULL}
+};
+
+static PyGetSetDef BufferedRandom_getset[] = {
+ {"closed", (getter)BufferedIOMixin_closed_get, NULL, NULL},
+ {0}
+};
+
+
+PyTypeObject PyBufferedRandom_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "BufferedRandom", /*tp_name*/
+ sizeof(BufferedObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)BufferedObject_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare */
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ BufferedRandom_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ offsetof(BufferedObject, weakreflist), /*tp_weaklistoffset*/
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BufferedRandom_methods, /* tp_methods */
+ BufferedRandom_members, /* tp_members */
+ BufferedRandom_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /*tp_dict*/
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ offsetof(BufferedObject, dict), /*tp_dictoffset*/
+ (initproc)BufferedRandom_init, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
Modified: sandbox/trunk/io-c/_fileio.c
==============================================================================
--- sandbox/trunk/io-c/_fileio.c (original)
+++ sandbox/trunk/io-c/_fileio.c Fri Nov 7 01:26:36 2008
@@ -6,8 +6,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <stddef.h> /* For offsetof */
-
-extern PyObject *PyRawIOBase;
+#include "_iomodule.h"
/*
* Known likely problems:
@@ -76,7 +75,7 @@
return NULL;
}
- return PyObject_CallMethod(PyRawIOBase, "close", "O", self);
+ return PyObject_CallMethod(&PyRawIOBase_Type, "close", "O", self);
}
static PyObject *
Added: sandbox/trunk/io-c/_iobase.c
==============================================================================
--- (empty file)
+++ sandbox/trunk/io-c/_iobase.c Fri Nov 7 01:26:36 2008
@@ -0,0 +1,757 @@
+#include "Python.h"
+#include "structmember.h"
+#include "_iomodule.h"
+
+/*
+ * IOBase class, an abstract class
+ */
+
+PyDoc_STRVAR(IOBase_doc,
+ "The abstract base class for all I/O classes, acting on streams of\n"
+ "bytes. There is no public constructor.\n"
+ "\n"
+ "This class provides dummy implementations for many methods that\n"
+ "derived classes can override selectively; the default implementations\n"
+ "represent a file that cannot be read, written or seeked.\n"
+ "\n"
+ "Even though IOBase does not declare read, readinto, or write because\n"
+ "their signatures will vary, implementations and clients should\n"
+ "consider those methods part of the interface. Also, implementations\n"
+ "may raise a IOError when operations they do not support are called.\n"
+ "\n"
+ "The basic type used for binary data read from or written to a file is\n"
+ "bytes. bytearrays are accepted too, and in some cases (such as\n"
+ "readinto) needed. Text I/O classes work with str data.\n"
+ "\n"
+ "Note that calling any method (even inquiries) on a closed stream is\n"
+ "undefined. Implementations may raise IOError in this case.\n"
+ "\n"
+ "IOBase (and its subclasses) support the iterator protocol, meaning\n"
+ "that an IOBase object can be iterated over yielding the lines in a\n"
+ "stream.\n"
+ "\n"
+ "IOBase also supports the :keyword:`with` statement. In this example,\n"
+ "fp is closed after the suite of the with statment is complete:\n"
+ "\n"
+ "with open('spam.txt', 'r') as fp:\n"
+ " fp.write('Spam and eggs!')\n");
+
+/* Internal methods */
+static PyObject *
+IOBase_unsupported(const char* message)
+{
+ PyErr_SetString(PyIOExc_UnsupportedOperation, message);
+ return NULL;
+}
+
+/* Positionning */
+
+PyDoc_STRVAR(IOBase_seek_doc,
+ "Change stream position.\n"
+ "\n"
+ "Change the stream position to byte offset offset. offset is\n"
+ "interpreted relative to the position indicated by whence. Values\n"
+ "for whence are:\n"
+ "\n"
+ "* 0 -- start of stream (the default); offset should be zero or positive\n"
+ "* 1 -- current stream position; offset may be negative\n"
+ "* 2 -- end of stream; offset is usually negative\n"
+ "\n"
+ "Return the new absolute position.");
+
+static PyObject*
+IOBase_seek(PyObject *self, PyObject *args)
+{
+ return IOBase_unsupported("seek");
+}
+
+PyDoc_STRVAR(IOBase_tell_doc,
+ "Return current stream position.");
+
+static PyObject *
+IOBase_tell(PyObject *self, PyObject *args)
+{
+ return PyObject_CallMethod(self, "tell", "ii", 0, 1);
+}
+
+PyDoc_STRVAR(IOBase_truncate_doc,
+ "Truncate file to size bytes.\n"
+ "\n"
+ "Size defaults to the current IO position as reported by tell(). Return\n"
+ "the new size.");
+
+static PyObject*
+IOBase_truncate(PyObject *self, PyObject *args)
+{
+ return IOBase_unsupported("seek");
+}
+
+/* Flush and close methods */
+
+PyDoc_STRVAR(IOBase_flush_doc,
+ "Flush write buffers, if applicable.\n"
+ "\n"
+ "This is not implemented for read-only and non-blocking streams.\n");
+
+static PyObject*
+IOBase_flush(PyObject *self, PyObject *args)
+{
+ /* XXX Should this return the number of bytes written??? */
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(IOBase_close_doc,
+ "Flush and close the IO object.\n"
+ "\n"
+ "This method has no effect if the file is already closed.\n");
+
+static int
+IOBase_closed(PyObject *self)
+{
+ return PyObject_HasAttrString(self, "__IOBase_closed");
+}
+
+static PyObject *
+IOBase_closed_get(PyObject *self, void *context)
+{
+ return PyBool_FromLong(IOBase_closed(self));
+}
+
+
+PyObject *
+_PyIOBase_checkClosed(PyObject *self, PyObject *unused)
+{
+ if (IOBase_closed(self)) {
+ PyErr_SetString(PyExc_ValueError, "I/O operation on closed file.");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+IOBase_close(PyObject *self, PyObject *args)
+{
+ PyObject *res;
+
+ if (IOBase_closed(self))
+ Py_RETURN_NONE;
+
+ PyObject_SetAttrString(self, "__IOBase_closed", Py_True);
+
+ res = PyObject_CallMethod(self, "flush", NULL);
+ if (res == NULL) {
+ /* If flush() fails, just give up */
+ if (PyErr_ExceptionMatches(PyExc_IOError))
+ PyErr_Clear();
+ else
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static void
+IOBase_del(PyObject *self)
+{
+ PyObject *res = PyObject_CallMethod(self, "flush", NULL);
+ if (res == NULL) {
+ /* At program exit time, it's possible that globals have already been
+ * deleted, and then the close() call might fail. Since there's
+ * nothing we can do about such failures and they annoy the end
+ * users, we suppress the traceback.
+ */
+ PyErr_Clear();
+ }
+}
+
+/* Inquiry methods */
+
+PyDoc_STRVAR(IOBase_seekable_doc,
+ "Return whether object supports random access.\n"
+ "\n"
+ "If False, seek(), tell() and truncate() will raise IOError.\n"
+ "This method may need to do a test seek().");
+
+static PyObject*
+IOBase_seekable(PyObject *self, PyObject *args)
+{
+ Py_RETURN_FALSE;
+}
+
+PyObject*
+_PyIOBase_checkSeekable(PyObject *self, PyObject *unused)
+{
+ PyObject *res = PyObject_CallMethod(self, "seekable", NULL);
+ if (res == NULL)
+ return NULL;
+ if (res != Py_True) {
+ Py_CLEAR(res);
+ PyErr_SetString(PyExc_IOError, "File or stream is not seekable.");
+ }
+ return res;
+}
+
+PyDoc_STRVAR(IOBase_readable_doc,
+ "Return whether object was opened for reading.\n"
+ "\n"
+ "If False, read() will raise IOError.");
+
+static PyObject*
+IOBase_readable(PyObject *self, PyObject *args)
+{
+ Py_RETURN_FALSE;
+}
+
+/* May be called with any object */
+PyObject*
+_PyIOBase_checkReadable(PyObject *self, PyObject *unused)
+{
+ PyObject *res = PyObject_CallMethod(self, "readable", NULL);
+ if (res == NULL)
+ return NULL;
+ if (res != Py_True) {
+ Py_CLEAR(res);
+ PyErr_SetString(PyExc_IOError, "File or stream is not readable.");
+ }
+ return res;
+}
+
+PyDoc_STRVAR(IOBase_writable_doc,
+ "Return whether object was opened for writing.\n"
+ "\n"
+ "If False, read() will raise IOError.");
+
+static PyObject*
+IOBase_writable(PyObject *self, PyObject *args)
+{
+ Py_RETURN_FALSE;
+}
+
+/* May be called with any object */
+PyObject*
+_PyIOBase_checkWritable(PyObject *self, PyObject *unused)
+{
+ PyObject *res = PyObject_CallMethod(self, "writable", NULL);
+ if (res == NULL)
+ return NULL;
+ if (res != Py_True) {
+ Py_CLEAR(res);
+ PyErr_SetString(PyExc_IOError, "File or stream is not writable.");
+ }
+ return res;
+}
+
+/* Context manager */
+
+static PyObject *
+IOBase_enter(PyObject *self, PyObject *args)
+{
+ if (_PyIOBase_checkClosed(self, NULL) == NULL)
+ return NULL;
+
+ Py_INCREF(self);
+ return self;
+}
+
+static PyObject *
+IOBase_exit(PyObject *self, PyObject *args)
+{
+ return PyObject_CallMethod(self, "close", NULL);
+}
+
+/* Lower-level APIs */
+
+/* XXX Should these be present even if unimplemented? */
+
+PyDoc_STRVAR(IOBase_fileno_doc,
+ "Returns underlying file descriptor if one exists.\n"
+ "\n"
+ "An IOError is raised if the IO object does not use a file descriptor.\n");
+
+static PyObject *
+IOBase_fileno(PyObject *self, PyObject *args)
+{
+ return IOBase_unsupported("fileno");
+}
+
+PyDoc_STRVAR(IOBase_isatty_doc,
+ "Return whether this is an 'interactive' stream.\n"
+ "\n"
+ "Return False if it can't be determined.\n");
+
+static PyObject *
+IOBase_isatty(PyObject *self, PyObject *args)
+{
+ if (_PyIOBase_checkClosed(self, NULL) == NULL)
+ return NULL;
+ Py_RETURN_FALSE;
+}
+
+/* Readline(s) and writelines */
+
+PyDoc_STRVAR(IOBase_readline_doc,
+ "Read and return a line from the stream.\n"
+ "\n"
+ "If limit is specified, at most limit bytes will be read.\n"
+ "\n"
+ "The line terminator is always b'\n' for binary files; for text\n"
+ "files, the newlines argument to open can be used to select the line\n"
+ "terminator(s) recognized.\n");
+
+static PyObject *
+IOBase_readline(PyObject *self, PyObject *args)
+{
+ /* For backwards compatibility, a (slowish) readline(). */
+
+ Py_ssize_t limit = -1;
+ int has_peek = 0;
+ PyObject *buffer, *result;
+ Py_ssize_t old_size = -1;
+
+ if (!PyArg_ParseTuple(args, "|n:readline", &limit)) {
+ return NULL;
+ }
+
+ if (_PyIOBase_checkClosed(self, NULL) == NULL)
+ return NULL;
+
+ if (PyObject_HasAttrString(self, "peek"))
+ has_peek = 1;
+
+ buffer = PyByteArray_FromStringAndSize(NULL, 0);
+ if (buffer == NULL)
+ return NULL;
+
+ while (limit < 0 || Py_SIZE(buffer) < limit) {
+ Py_ssize_t nreadahead = 1;
+ PyObject *b;
+
+ if (has_peek) {
+ PyObject *readahead = PyObject_CallMethod(self, "peek", "i", 1);
+
+ assert (PyBytes_Check(readahead));
+
+ if (readahead == NULL)
+ goto fail;
+ if (PyBytes_GET_SIZE(readahead) > 0) {
+ Py_ssize_t n = 0;
+ const char *buf = PyBytes_AS_STRING(readahead);
+ if (limit >= 0) {
+ do {
+ if (n >= PyBytes_GET_SIZE(readahead) || n >= limit)
+ break;
+ if (buf[n] == '\n')
+ {
+ n++;
+ break;
+ }
+ n++;
+ } while (1);
+ }
+ else {
+ do {
+ if (n >= PyBytes_GET_SIZE(readahead))
+ break;
+ if (buf[n] == '\n')
+ {
+ n++;
+ break;
+ }
+ n++;
+ } while (1);
+ }
+ nreadahead = n;
+ }
+ }
+
+ b = PyObject_CallMethod(self, "read", "n", nreadahead);
+
+ if (b == NULL)
+ goto fail;
+
+ assert (PyBytes_Check(b));
+
+ if (Py_SIZE(b) == 0)
+ break;
+
+ old_size = Py_SIZE(buffer);
+ PyByteArray_Resize(buffer, old_size + Py_SIZE(b));
+ memcpy(PyByteArray_AS_STRING(buffer) + old_size, PyBytes_AS_STRING(b), Py_SIZE(b));
+
+ Py_DECREF(b);
+
+ if (PyByteArray_AS_STRING(buffer)[PyByteArray_GET_SIZE(buffer) - 1] == '\n')
+ break;
+ }
+
+ result = PyBytes_FromStringAndSize(PyByteArray_AS_STRING(buffer),
+ PyByteArray_GET_SIZE(buffer));
+ Py_DECREF(buffer);
+ return result;
+ fail:
+ Py_DECREF(buffer);
+ return NULL;
+}
+
+static PyObject *
+IOBase_iter(PyObject *self, PyObject *args)
+{
+ if (_PyIOBase_checkClosed(self, NULL) == NULL)
+ return NULL;
+
+ Py_INCREF(self);
+ return self;
+}
+
+static PyObject *
+IOBase_next(PyObject *self, PyObject *args)
+{
+ PyObject *line = PyObject_CallMethod(self, "readline", NULL);
+
+ if (line == NULL)
+ return NULL;
+
+ assert (PyBytes_Check(line));
+
+ if (PyBytes_GET_SIZE(line) == 0) {
+ Py_DECREF(line);
+ return NULL;
+ }
+
+ return line;
+}
+
+PyDoc_STRVAR(IOBase_readlines_doc,
+ "Return a list of lines from the stream.\n"
+ "\n"
+ "hint can be specified to control the number of lines read: no more\n"
+ "lines will be read if the total size (in bytes/characters) of all\n"
+ "lines so far exceeds hint.");
+
+static PyObject *
+IOBase_readlines(PyObject *self, PyObject *args)
+{
+ Py_ssize_t hint = -1, length = 0;
+ PyObject *line, *result;
+
+ if (!PyArg_ParseTuple(args, "|n:readlines", &hint)) {
+ return NULL;
+ }
+
+ result = PyList_New(0);
+ if (result == NULL)
+ return NULL;
+
+ if (hint <= 0) {
+ PyObject *ret = PyObject_CallMethod(result, "extend", "O", self);
+ if( ret == NULL) {
+ Py_DECREF(result);
+ return NULL;
+ }
+ Py_DECREF(ret);
+ return result;
+ }
+
+ while (1) {
+ line = PyObject_CallMethod(self, "__next__", NULL);
+ if (line == NULL) {
+ if (PyErr_Occurred()) {
+ Py_DECREF(result);
+ return NULL;
+ }
+ else
+ break; /* SopIteration raised */
+ }
+ assert (PyBytes_Check(line));
+
+ if (PyList_Append(result, line) < 0) {
+ Py_DECREF(line);
+ Py_DECREF(result);
+ return NULL;
+ }
+ length += Py_SIZE(line);
+ Py_DECREF(line);
+
+ if (length > hint)
+ break;
+ }
+ return result;
+}
+
+static PyObject *
+IOBase_writelines(PyObject *self, PyObject *args)
+{
+ PyObject *lines, *iter, *res;
+
+ if (!PyArg_ParseTuple(args, "O:writelines", &lines)) {
+ return NULL;
+ }
+
+ if (_PyIOBase_checkClosed(self, NULL) == NULL)
+ return NULL;
+
+ iter = PyObject_GetIter(lines);
+ if (iter == NULL)
+ return NULL;
+
+ while (1) {
+ PyObject *line = PyIter_Next(iter);
+ if(line == NULL) {
+ if (PyErr_Occurred()) {
+ Py_DECREF(iter);
+ return NULL;
+ }
+ else
+ break; /* Stop Iteration */
+ }
+
+ res = PyObject_CallMethod(self, "write", "O", line);
+ Py_DECREF(line);
+ if (res == NULL) {
+ Py_DECREF(iter);
+ return NULL;
+ }
+ Py_DECREF(res);
+ }
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef IOBase_methods[] = {
+ {"seek", IOBase_seek, METH_VARARGS},
+ {"tell", IOBase_tell, METH_NOARGS},
+ {"truncate", IOBase_truncate, METH_VARARGS},
+ {"flush", IOBase_flush, METH_NOARGS},
+ {"close", IOBase_close, METH_NOARGS},
+
+ {"seekable", IOBase_seekable, METH_NOARGS},
+ {"readable", IOBase_readable, METH_NOARGS},
+ {"writable", IOBase_writable, METH_NOARGS},
+
+ {"_checkClosed", _PyIOBase_checkClosed, METH_NOARGS},
+ {"_checkSeekable", _PyIOBase_checkSeekable, METH_NOARGS},
+ {"_checkReadable", _PyIOBase_checkReadable, METH_NOARGS},
+ {"_checkWritable", _PyIOBase_checkWritable, METH_NOARGS},
+
+ {"fileno", IOBase_fileno, METH_NOARGS},
+ {"isatty", IOBase_isatty, METH_NOARGS},
+
+ {"__enter__", IOBase_enter, METH_NOARGS},
+ {"__exit__", IOBase_exit, METH_VARARGS},
+
+ {"__iter__", IOBase_iter, METH_NOARGS},
+ {"__next__", IOBase_next, METH_NOARGS},
+
+ {"readline", IOBase_readline, METH_VARARGS},
+ {"readlines", IOBase_readlines, METH_VARARGS},
+ {"writelines", IOBase_readlines, METH_VARARGS},
+
+ {NULL, NULL}
+};
+
+static PyGetSetDef IOBase_getset[] = {
+ {"closed", (getter)IOBase_closed_get, NULL, NULL},
+ {0}
+};
+
+
+PyTypeObject PyIOBase_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "IOBase", /*tp_name*/
+ 0, /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare */
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ IOBase_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ IOBase_methods, /* tp_methods */
+ 0, /* tp_members */
+ IOBase_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+ IOBase_del, /* tp_del */
+};
+
+
+
+/*
+ * RawIOBase class, Inherits from IOBase.
+ */
+PyDoc_STRVAR(RawIOBase_doc,
+ "Base class for raw binary I/O.");
+
+/*
+ * The read() method is implemented by calling readinto(); derived classes
+ * that want to support read() only need to implement readinto() as a
+ * primitive operation. In general, readinto() can be more efficient than
+ * read().
+ *
+ * (It would be tempting to also provide an implementation of readinto() in
+ * terms of read(), in case the latter is a more suitable primitive operation,
+ * but that would lead to nasty recursion in case a subclass doesn't implement
+ * either.)
+*/
+
+static PyObject *
+RawIOBase_read(PyObject *self, PyObject *args)
+{
+ Py_ssize_t n = -1;
+ PyObject *b, *res;
+
+ if (!PyArg_ParseTuple(args, "|n:read", &n)) {
+ return NULL;
+ }
+
+ if (n < 0)
+ return PyObject_CallMethod(self, "readall", NULL);
+
+ b = PyByteArray_FromStringAndSize(NULL, n);
+ if (b == NULL)
+ return NULL;
+
+ res = PyObject_CallMethod(self, "readinto", "O", b);
+ if (res == NULL) {
+ Py_DECREF(b);
+ return NULL;
+ }
+
+ n = PyNumber_AsSsize_t(res, PyExc_ValueError);
+ Py_DECREF(res);
+ if (n == -1 && PyErr_Occurred()) {
+ Py_DECREF(b);
+ return NULL;
+ }
+
+ res = PyBytes_FromStringAndSize(PyByteArray_AsString(b), n);
+ Py_DECREF(b);
+ return res;
+}
+
+
+PyDoc_STRVAR(RawIOBase_readall_doc,
+ "Read until EOF, using multiple read() call.");
+
+static PyObject *
+RawIOBase_readall(PyObject *self, PyObject *args)
+{
+ PyObject *b = NULL;
+ Py_ssize_t cursize = 0;
+
+ while (1) {
+ Py_ssize_t length;
+ PyObject *data = PyObject_CallMethod(self, "read",
+ "i", DEFAULT_BUFFER_SIZE);
+
+ if (!data) {
+ Py_XDECREF(b);
+ return NULL;
+ }
+
+ if (!PyBytes_Check(data)) {
+ Py_XDECREF(b);
+ Py_DECREF(data);
+ PyErr_SetString(PyExc_TypeError, "read() should return bytes");
+ return NULL;
+ }
+
+ length = Py_SIZE(data);
+
+ if (b == NULL)
+ b = data;
+ else if (length != 0) {
+
+ _PyBytes_Resize(&b, cursize + length);
+ if (b == NULL) {
+ Py_DECREF(data);
+ return NULL;
+ }
+
+ memcpy(PyBytes_AS_STRING(b) + cursize,
+ PyBytes_AS_STRING(data), length);
+ Py_DECREF(data);
+ }
+
+ if (length == 0)
+ break;
+ }
+
+ return b;
+
+}
+
+static PyMethodDef RawIOBase_methods[] = {
+ {"read", RawIOBase_read, METH_VARARGS},
+ {"readall", RawIOBase_readall, METH_NOARGS, RawIOBase_readall_doc},
+ {NULL, NULL}
+};
+
+PyTypeObject PyRawIOBase_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "RawIOBase", /*tp_name*/
+ 0, /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ 0, /*tp_dealloc*/
+ 0, /*tp_print*/
+ 0, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare */
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash */
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ RawIOBase_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ RawIOBase_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PyIOBase_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
Added: sandbox/trunk/io-c/_iomodule.h
==============================================================================
--- (empty file)
+++ sandbox/trunk/io-c/_iomodule.h Fri Nov 7 01:26:36 2008
@@ -0,0 +1,31 @@
+/*
+ * Declarations shared between the different parts of the io module
+ */
+
+extern PyTypeObject PyFileIO_Type;
+extern PyTypeObject PyBytesIO_Type;
+extern PyTypeObject PyIOBase_Type;
+extern PyTypeObject PyRawIOBase_Type;
+extern PyTypeObject PyBufferedIOBase_Type;
+extern PyTypeObject PyBufferedReader_Type;
+extern PyTypeObject PyBufferedWriter_Type;
+extern PyTypeObject PyBufferedRWPair_Type;
+extern PyTypeObject PyBufferedRandom_Type;
+
+extern PyObject* _PyIOBase_checkReadable(PyObject *self, PyObject *unused);
+extern PyObject* _PyIOBase_checkWritable(PyObject *self, PyObject *unused);
+extern PyObject* _PyIOBase_checkSeekable(PyObject *self, PyObject *unused);
+
+extern PyObject* PyIOExc_UnsupportedOperation;
+
+#define DEFAULT_BUFFER_SIZE (8 * 1024) /* bytes */
+
+typedef struct {
+ PyException_HEAD
+ PyObject *myerrno;
+ PyObject *strerror;
+ PyObject *filename; /* Not used, but part of the IOError object */
+ Py_ssize_t written;
+} PyBlockingIOErrorObject;
+PyObject *PyExc_BlockingIOError;
+
Modified: sandbox/trunk/io-c/build.py
==============================================================================
--- sandbox/trunk/io-c/build.py (original)
+++ sandbox/trunk/io-c/build.py Fri Nov 7 01:26:36 2008
@@ -3,7 +3,8 @@
from distutils.command.build_ext import build_ext
def compile():
- sources = ['io.c', '_fileio.c', '_bytesio.c']
+ sources = ['io.c', '_iobase.c', '_bufferedio.c',
+ '_fileio.c', '_bytesio.c']
sources = [os.path.join(os.path.dirname(__file__), s) for s in sources]
io_ext = Extension('_io', sources)
dist = Distribution({'name': '_io', 'ext_modules': [io_ext]})
Modified: sandbox/trunk/io-c/io.c
==============================================================================
--- sandbox/trunk/io-c/io.c (original)
+++ sandbox/trunk/io-c/io.c Fri Nov 7 01:26:36 2008
@@ -1,15 +1,12 @@
#include <python.h>
#include "structmember.h"
-#include "pythread.h"
+#include "_iomodule.h"
-extern PyTypeObject PyFileIO_Type;
-extern PyTypeObject PyBytesIO_Type;
+PyObject *PyIOExc_UnsupportedOperation;
+
static PyObject *io_py_module;
-/* open() uses st_blksize whenever we can */
-#define DEFAULT_BUFFER_SIZE (8 * 1024) /* bytes */
-
PyDoc_STRVAR(module_doc,
"The io module provides the Python interfaces to stream handling. The\n"
@@ -52,15 +49,6 @@
* BlockingIOError extends IOError
*/
-typedef struct {
- PyException_HEAD
- PyObject *myerrno;
- PyObject *strerror;
- PyObject *filename; /* Not used, but part of the IOError object */
- Py_ssize_t written;
-} PyBlockingIOErrorObject;
-
-
static int
BlockingIOError_init(PyBlockingIOErrorObject *self, PyObject *args,
PyObject *kwds)
@@ -523,2397 +511,6 @@
}
-static PyObject* PyExc_UnsupportedOperation;
-
-/*
- * IOBase class, an abstract class
- */
-
-PyDoc_STRVAR(IOBase_doc,
- "The abstract base class for all I/O classes, acting on streams of\n"
- "bytes. There is no public constructor.\n"
- "\n"
- "This class provides dummy implementations for many methods that\n"
- "derived classes can override selectively; the default implementations\n"
- "represent a file that cannot be read, written or seeked.\n"
- "\n"
- "Even though IOBase does not declare read, readinto, or write because\n"
- "their signatures will vary, implementations and clients should\n"
- "consider those methods part of the interface. Also, implementations\n"
- "may raise a IOError when operations they do not support are called.\n"
- "\n"
- "The basic type used for binary data read from or written to a file is\n"
- "bytes. bytearrays are accepted too, and in some cases (such as\n"
- "readinto) needed. Text I/O classes work with str data.\n"
- "\n"
- "Note that calling any method (even inquiries) on a closed stream is\n"
- "undefined. Implementations may raise IOError in this case.\n"
- "\n"
- "IOBase (and its subclasses) support the iterator protocol, meaning\n"
- "that an IOBase object can be iterated over yielding the lines in a\n"
- "stream.\n"
- "\n"
- "IOBase also supports the :keyword:`with` statement. In this example,\n"
- "fp is closed after the suite of the with statment is complete:\n"
- "\n"
- "with open('spam.txt', 'r') as fp:\n"
- " fp.write('Spam and eggs!')\n");
-
-/* Internal methods */
-static PyObject *
-IOBase_unsupported(const char* message)
-{
- PyErr_SetString(PyExc_UnsupportedOperation, message);
- return NULL;
-}
-
-/* Positionning */
-
-PyDoc_STRVAR(IOBase_seek_doc,
- "Change stream position.\n"
- "\n"
- "Change the stream position to byte offset offset. offset is\n"
- "interpreted relative to the position indicated by whence. Values\n"
- "for whence are:\n"
- "\n"
- "* 0 -- start of stream (the default); offset should be zero or positive\n"
- "* 1 -- current stream position; offset may be negative\n"
- "* 2 -- end of stream; offset is usually negative\n"
- "\n"
- "Return the new absolute position.");
-
-static PyObject*
-IOBase_seek(PyObject *self, PyObject *args)
-{
- return IOBase_unsupported("seek");
-}
-
-PyDoc_STRVAR(IOBase_tell_doc,
- "Return current stream position.");
-
-static PyObject *
-IOBase_tell(PyObject *self, PyObject *args)
-{
- return PyObject_CallMethod(self, "tell", "ii", 0, 1);
-}
-
-PyDoc_STRVAR(IOBase_truncate_doc,
- "Truncate file to size bytes.\n"
- "\n"
- "Size defaults to the current IO position as reported by tell(). Return\n"
- "the new size.");
-
-static PyObject*
-IOBase_truncate(PyObject *self, PyObject *args)
-{
- return IOBase_unsupported("seek");
-}
-
-/* Flush and close methods */
-
-PyDoc_STRVAR(IOBase_flush_doc,
- "Flush write buffers, if applicable.\n"
- "\n"
- "This is not implemented for read-only and non-blocking streams.\n");
-
-static PyObject*
-IOBase_flush(PyObject *self, PyObject *args)
-{
- /* XXX Should this return the number of bytes written??? */
- Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(IOBase_close_doc,
- "Flush and close the IO object.\n"
- "\n"
- "This method has no effect if the file is already closed.\n");
-
-static int
-IOBase_closed(PyObject *self)
-{
- return PyObject_HasAttrString(self, "__IOBase_closed");
-}
-
-static PyObject *
-IOBase_closed_get(PyObject *self, void *context)
-{
- return PyBool_FromLong(IOBase_closed(self));
-}
-
-
-static PyObject *
-IOBase_checkClosed(PyObject *self, PyObject *unused)
-{
- if (IOBase_closed(self)) {
- PyErr_SetString(PyExc_ValueError, "I/O operation on closed file.");
- return NULL;
- }
- Py_RETURN_NONE;
-}
-
-static PyObject*
-IOBase_close(PyObject *self, PyObject *args)
-{
- PyObject *res;
-
- if (IOBase_closed(self))
- Py_RETURN_NONE;
-
- PyObject_SetAttrString(self, "__IOBase_closed", Py_True);
-
- res = PyObject_CallMethod(self, "flush", NULL);
- if (res == NULL) {
- /* If flush() fails, just give up */
- if (PyErr_ExceptionMatches(PyExc_IOError))
- PyErr_Clear();
- else
- return NULL;
- }
- Py_RETURN_NONE;
-}
-
-static void
-IOBase_del(PyObject *self)
-{
- PyObject *res = PyObject_CallMethod(self, "flush", NULL);
- if (res == NULL) {
- /* At program exit time, it's possible that globals have already been
- * deleted, and then the close() call might fail. Since there's
- * nothing we can do about such failures and they annoy the end
- * users, we suppress the traceback.
- */
- PyErr_Clear();
- }
-}
-
-/* Inquiry methods */
-
-PyDoc_STRVAR(IOBase_seekable_doc,
- "Return whether object supports random access.\n"
- "\n"
- "If False, seek(), tell() and truncate() will raise IOError.\n"
- "This method may need to do a test seek().");
-
-static PyObject*
-IOBase_seekable(PyObject *self, PyObject *args)
-{
- Py_RETURN_FALSE;
-}
-
-static PyObject*
-IOBase_checkSeekable(PyObject *self, PyObject *unused)
-{
- PyObject *res = PyObject_CallMethod(self, "seekable", NULL);
- if (res == NULL)
- return NULL;
- if (res != Py_True) {
- Py_CLEAR(res);
- PyErr_SetString(PyExc_IOError, "File or stream is not seekable.");
- }
- return res;
-}
-
-PyDoc_STRVAR(IOBase_readable_doc,
- "Return whether object was opened for reading.\n"
- "\n"
- "If False, read() will raise IOError.");
-
-static PyObject*
-IOBase_readable(PyObject *self, PyObject *args)
-{
- Py_RETURN_FALSE;
-}
-
-/* May be called with any object */
-static PyObject*
-IOBase_checkReadable(PyObject *self, PyObject *unused)
-{
- PyObject *res = PyObject_CallMethod(self, "readable", NULL);
- if (res == NULL)
- return NULL;
- if (res != Py_True) {
- Py_CLEAR(res);
- PyErr_SetString(PyExc_IOError, "File or stream is not readable.");
- }
- return res;
-}
-
-PyDoc_STRVAR(IOBase_writable_doc,
- "Return whether object was opened for writing.\n"
- "\n"
- "If False, read() will raise IOError.");
-
-static PyObject*
-IOBase_writable(PyObject *self, PyObject *args)
-{
- Py_RETURN_FALSE;
-}
-
-/* May be called with any object */
-static PyObject*
-IOBase_checkWritable(PyObject *self, PyObject *unused)
-{
- PyObject *res = PyObject_CallMethod(self, "writable", NULL);
- if (res == NULL)
- return NULL;
- if (res != Py_True) {
- Py_CLEAR(res);
- PyErr_SetString(PyExc_IOError, "File or stream is not writable.");
- }
- return res;
-}
-
-/* Context manager */
-
-static PyObject *
-IOBase_enter(PyObject *self, PyObject *args)
-{
- if (IOBase_checkClosed(self, NULL) == NULL)
- return NULL;
-
- Py_INCREF(self);
- return self;
-}
-
-static PyObject *
-IOBase_exit(PyObject *self, PyObject *args)
-{
- return PyObject_CallMethod(self, "close", NULL);
-}
-
-/* Lower-level APIs */
-
-/* XXX Should these be present even if unimplemented? */
-
-PyDoc_STRVAR(IOBase_fileno_doc,
- "Returns underlying file descriptor if one exists.\n"
- "\n"
- "An IOError is raised if the IO object does not use a file descriptor.\n");
-
-static PyObject *
-IOBase_fileno(PyObject *self, PyObject *args)
-{
- return IOBase_unsupported("fileno");
-}
-
-PyDoc_STRVAR(IOBase_isatty_doc,
- "Return whether this is an 'interactive' stream.\n"
- "\n"
- "Return False if it can't be determined.\n");
-
-static PyObject *
-IOBase_isatty(PyObject *self, PyObject *args)
-{
- if (IOBase_checkClosed(self, NULL) == NULL)
- return NULL;
- Py_RETURN_FALSE;
-}
-
-/* Readline(s) and writelines */
-
-PyDoc_STRVAR(IOBase_readline_doc,
- "Read and return a line from the stream.\n"
- "\n"
- "If limit is specified, at most limit bytes will be read.\n"
- "\n"
- "The line terminator is always b'\n' for binary files; for text\n"
- "files, the newlines argument to open can be used to select the line\n"
- "terminator(s) recognized.\n");
-
-static PyObject *
-IOBase_readline(PyObject *self, PyObject *args)
-{
- /* For backwards compatibility, a (slowish) readline(). */
-
- Py_ssize_t limit = -1;
- int has_peek = 0;
- PyObject *buffer, *result;
- Py_ssize_t old_size = -1;
-
- if (!PyArg_ParseTuple(args, "|n:readline", &limit)) {
- return NULL;
- }
-
- if (IOBase_checkClosed(self, NULL) == NULL)
- return NULL;
-
- if (PyObject_HasAttrString(self, "peek"))
- has_peek = 1;
-
- buffer = PyByteArray_FromStringAndSize(NULL, 0);
- if (buffer == NULL)
- return NULL;
-
- while (limit < 0 || Py_SIZE(buffer) < limit) {
- Py_ssize_t nreadahead = 1;
- PyObject *b;
-
- if (has_peek) {
- PyObject *readahead = PyObject_CallMethod(self, "peek", "i", 1);
-
- assert (PyBytes_Check(readahead));
-
- if (readahead == NULL)
- goto fail;
- if (PyBytes_GET_SIZE(readahead) > 0) {
- Py_ssize_t n = 0;
- const char *buf = PyBytes_AS_STRING(readahead);
- if (limit >= 0) {
- do {
- if (n >= PyBytes_GET_SIZE(readahead) || n >= limit)
- break;
- if (buf[n] == '\n')
- {
- n++;
- break;
- }
- n++;
- } while (1);
- }
- else {
- do {
- if (n >= PyBytes_GET_SIZE(readahead))
- break;
- if (buf[n] == '\n')
- {
- n++;
- break;
- }
- n++;
- } while (1);
- }
- nreadahead = n;
- }
- }
-
- b = PyObject_CallMethod(self, "read", "n", nreadahead);
-
- if (b == NULL)
- goto fail;
-
- assert (PyBytes_Check(b));
-
- if (Py_SIZE(b) == 0)
- break;
-
- old_size = Py_SIZE(buffer);
- PyByteArray_Resize(buffer, old_size + Py_SIZE(b));
- memcpy(PyByteArray_AS_STRING(buffer) + old_size, PyBytes_AS_STRING(b), Py_SIZE(b));
-
- Py_DECREF(b);
-
- if (PyByteArray_AS_STRING(buffer)[PyByteArray_GET_SIZE(buffer) - 1] == '\n')
- break;
- }
-
- result = PyBytes_FromStringAndSize(PyByteArray_AS_STRING(buffer),
- PyByteArray_GET_SIZE(buffer));
- Py_DECREF(buffer);
- return result;
- fail:
- Py_DECREF(buffer);
- return NULL;
-}
-
-static PyObject *
-IOBase_iter(PyObject *self, PyObject *args)
-{
- if (IOBase_checkClosed(self, NULL) == NULL)
- return NULL;
-
- Py_INCREF(self);
- return self;
-}
-
-static PyObject *
-IOBase_next(PyObject *self, PyObject *args)
-{
- PyObject *line = PyObject_CallMethod(self, "readline", NULL);
-
- if (line == NULL)
- return NULL;
-
- assert (PyBytes_Check(line));
-
- if (PyBytes_GET_SIZE(line) == 0) {
- Py_DECREF(line);
- return NULL;
- }
-
- return line;
-}
-
-PyDoc_STRVAR(IOBase_readlines_doc,
- "Return a list of lines from the stream.\n"
- "\n"
- "hint can be specified to control the number of lines read: no more\n"
- "lines will be read if the total size (in bytes/characters) of all\n"
- "lines so far exceeds hint.");
-
-static PyObject *
-IOBase_readlines(PyObject *self, PyObject *args)
-{
- Py_ssize_t hint = -1, length = 0;
- PyObject *line, *result;
-
- if (!PyArg_ParseTuple(args, "|n:readlines", &hint)) {
- return NULL;
- }
-
- result = PyList_New(0);
- if (result == NULL)
- return NULL;
-
- if (hint <= 0) {
- PyObject *ret = PyObject_CallMethod(result, "extend", "O", self);
- if( ret == NULL) {
- Py_DECREF(result);
- return NULL;
- }
- Py_DECREF(ret);
- return result;
- }
-
- while (1) {
- line = PyObject_CallMethod(self, "__next__", NULL);
- if (line == NULL) {
- if (PyErr_Occurred()) {
- Py_DECREF(result);
- return NULL;
- }
- else
- break; /* SopIteration raised */
- }
- assert (PyBytes_Check(line));
-
- if (PyList_Append(result, line) < 0) {
- Py_DECREF(line);
- Py_DECREF(result);
- return NULL;
- }
- length += Py_SIZE(line);
- Py_DECREF(line);
-
- if (length > hint)
- break;
- }
- return result;
-}
-
-static PyObject *
-IOBase_writelines(PyObject *self, PyObject *args)
-{
- PyObject *lines, *iter, *res;
-
- if (!PyArg_ParseTuple(args, "O:writelines", &lines)) {
- return NULL;
- }
-
- if (IOBase_checkClosed(self, NULL) == NULL)
- return NULL;
-
- iter = PyObject_GetIter(lines);
- if (iter == NULL)
- return NULL;
-
- while (1) {
- PyObject *line = PyIter_Next(iter);
- if(line == NULL) {
- if (PyErr_Occurred()) {
- Py_DECREF(iter);
- return NULL;
- }
- else
- break; /* Stop Iteration */
- }
-
- res = PyObject_CallMethod(self, "write", "O", line);
- Py_DECREF(line);
- if (res == NULL) {
- Py_DECREF(iter);
- return NULL;
- }
- Py_DECREF(res);
- }
- Py_RETURN_NONE;
-}
-
-static PyMethodDef IOBase_methods[] = {
- {"seek", IOBase_seek, METH_VARARGS},
- {"tell", IOBase_tell, METH_NOARGS},
- {"truncate", IOBase_truncate, METH_VARARGS},
- {"flush", IOBase_flush, METH_NOARGS},
- {"close", IOBase_close, METH_NOARGS},
-
- {"seekable", IOBase_seekable, METH_NOARGS},
- {"readable", IOBase_readable, METH_NOARGS},
- {"writable", IOBase_writable, METH_NOARGS},
-
- {"_checkClosed", IOBase_checkClosed, METH_NOARGS},
- {"_checkSeekable", IOBase_checkSeekable, METH_NOARGS},
- {"_checkReadable", IOBase_checkReadable, METH_NOARGS},
- {"_checkWritable", IOBase_checkWritable, METH_NOARGS},
-
- {"fileno", IOBase_fileno, METH_NOARGS},
- {"isatty", IOBase_isatty, METH_NOARGS},
-
- {"__enter__", IOBase_enter, METH_NOARGS},
- {"__exit__", IOBase_exit, METH_VARARGS},
-
- {"__iter__", IOBase_iter, METH_NOARGS},
- {"__next__", IOBase_next, METH_NOARGS},
-
- {"readline", IOBase_readline, METH_VARARGS},
- {"readlines", IOBase_readlines, METH_VARARGS},
- {"writelines", IOBase_readlines, METH_VARARGS},
-
- {NULL, NULL}
-};
-
-static PyGetSetDef IOBase_getset[] = {
- {"closed", (getter)IOBase_closed_get, NULL, NULL},
- {0}
-};
-
-
-PyTypeObject _IOBase_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "IOBase", /*tp_name*/
- 0, /*tp_basicsize*/
- 0, /*tp_itemsize*/
- 0, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare */
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
- IOBase_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- IOBase_methods, /* tp_methods */
- 0, /* tp_members */
- IOBase_getset, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- PyType_GenericNew, /* tp_new */
- 0, /* tp_free */
- 0, /* tp_is_gc */
- 0, /* tp_bases */
- 0, /* tp_mro */
- 0, /* tp_cache */
- 0, /* tp_subclasses */
- 0, /* tp_weaklist */
- IOBase_del, /* tp_del */
-};
-PyObject *PyIOBase = (PyObject*)&_IOBase_Type;
-
-
-
-/*
- * RawIOBase class, Inherits from IOBase.
- */
-PyDoc_STRVAR(RawIOBase_doc,
- "Base class for raw binary I/O.");
-
-/*
- * The read() method is implemented by calling readinto(); derived classes
- * that want to support read() only need to implement readinto() as a
- * primitive operation. In general, readinto() can be more efficient than
- * read().
- *
- * (It would be tempting to also provide an implementation of readinto() in
- * terms of read(), in case the latter is a more suitable primitive operation,
- * but that would lead to nasty recursion in case a subclass doesn't implement
- * either.)
-*/
-
-static PyObject *
-RawIOBase_read(PyObject *self, PyObject *args)
-{
- Py_ssize_t n = -1;
- PyObject *b, *res;
-
- if (!PyArg_ParseTuple(args, "|n:read", &n)) {
- return NULL;
- }
-
- if (n < 0)
- return PyObject_CallMethod(self, "readall", NULL);
-
- b = PyByteArray_FromStringAndSize(NULL, n);
- if (b == NULL)
- return NULL;
-
- res = PyObject_CallMethod(self, "readinto", "O", b);
- if (res == NULL) {
- Py_DECREF(b);
- return NULL;
- }
-
- n = PyNumber_AsSsize_t(res, PyExc_ValueError);
- Py_DECREF(res);
- if (n == -1 && PyErr_Occurred()) {
- Py_DECREF(b);
- return NULL;
- }
-
- res = PyBytes_FromStringAndSize(PyByteArray_AsString(b), n);
- Py_DECREF(b);
- return res;
-}
-
-
-PyDoc_STRVAR(RawIOBase_readall_doc,
- "Read until EOF, using multiple read() call.");
-
-static PyObject *
-RawIOBase_readall(PyObject *self, PyObject *args)
-{
- PyObject *b = NULL;
- Py_ssize_t cursize = 0;
-
- while (1) {
- Py_ssize_t length;
- PyObject *data = PyObject_CallMethod(self, "read",
- "i", DEFAULT_BUFFER_SIZE);
-
- if (!data) {
- Py_XDECREF(b);
- return NULL;
- }
-
- if (!PyBytes_Check(data)) {
- Py_XDECREF(b);
- Py_DECREF(data);
- PyErr_SetString(PyExc_TypeError, "read() should return bytes");
- return NULL;
- }
-
- length = Py_SIZE(data);
-
- if (b == NULL)
- b = data;
- else if (length != 0) {
-
- _PyBytes_Resize(&b, cursize + length);
- if (b == NULL) {
- Py_DECREF(data);
- return NULL;
- }
-
- memcpy(PyBytes_AS_STRING(b) + cursize,
- PyBytes_AS_STRING(data), length);
- Py_DECREF(data);
- }
-
- if (length == 0)
- break;
- }
-
- return b;
-
-}
-
-static PyMethodDef RawIOBase_methods[] = {
- {"read", RawIOBase_read, METH_VARARGS},
- {"readall", RawIOBase_readall, METH_NOARGS, RawIOBase_readall_doc},
- {NULL, NULL}
-};
-
-PyTypeObject _RawIOBase_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "RawIOBase", /*tp_name*/
- 0, /*tp_basicsize*/
- 0, /*tp_itemsize*/
- 0, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare */
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
- RawIOBase_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- RawIOBase_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- &_IOBase_Type, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
-};
-PyObject *PyRawIOBase = (PyObject*)&_RawIOBase_Type;
-
-
-/*
- * BufferedIOBase class, inherits from IOBase.
- */
-PyDoc_STRVAR(BufferedIOBase_doc,
- "Base class for buffered IO objects.\n"
- "\n"
- "The main difference with RawIOBase is that the read() method\n"
- "supports omitting the size argument, and does not have a default\n"
- "implementation that defers to readinto().\n"
- "\n"
- "In addition, read(), readinto() and write() may raise\n"
- "BlockingIOError if the underlying raw stream is in non-blocking\n"
- "mode and not ready; unlike their raw counterparts, they will never\n"
- "return None.\n"
- "\n"
- "A typical implementation should not inherit from a RawIOBase\n"
- "implementation, but wrap one.\n"
- );
-
-static PyObject *
-BufferedIOBase_readinto(PyObject *self, PyObject *args)
-{
- Py_buffer buf;
- Py_ssize_t len;
- PyObject *data;
-
- if (!PyArg_ParseTuple(args, "w*:readinto", &buf)) {
- return NULL;
- }
-
- data = PyObject_CallMethod(self, "read", "n", buf.len);
- if (data == NULL)
- goto error;
-
- if (!PyBytes_Check(data)) {
- Py_DECREF(data);
- PyErr_SetString(PyExc_TypeError, "read() should return bytes");
- goto error;
- }
-
- len = Py_SIZE(data);
- memcpy(buf.buf, PyBytes_AS_STRING(data), len);
-
- PyBuffer_Release(&buf);
- Py_DECREF(data);
-
- return PyLong_FromSsize_t(len);
-
- error:
- PyBuffer_Release(&buf);
- return NULL;
-}
-
-static PyMethodDef BufferedIOBase_methods[] = {
- {"readinto", BufferedIOBase_readinto, METH_VARARGS},
- {NULL, NULL}
-};
-
-PyTypeObject _BufferedIOBase_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "BufferedIOBase", /*tp_name*/
- 0, /*tp_basicsize*/
- 0, /*tp_itemsize*/
- 0, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare */
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
- BufferedIOBase_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- BufferedIOBase_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- &_IOBase_Type, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
-};
-
-
-typedef struct {
- PyObject_HEAD
-
- PyObject *raw;
-
- PyObject *name;
- PyObject *mode;
-
- PyObject *read_buf;
- Py_ssize_t read_pos;
- PyThread_type_lock read_lock;
-
- PyObject *write_buf;
- PyThread_type_lock write_lock;
-
- Py_ssize_t buffer_size;
- Py_ssize_t max_buffer_size;
-
- PyObject *dict;
- PyObject *weakreflist;
-} BufferedObject;
-
-static void
-BufferedObject_dealloc(BufferedObject *self)
-{
- if (self->weakreflist != NULL)
- PyObject_ClearWeakRefs((PyObject *)self);
- Py_CLEAR(self->raw);
- Py_CLEAR(self->name);
- Py_CLEAR(self->mode);
- Py_CLEAR(self->read_buf);
- Py_CLEAR(self->write_buf);
- Py_CLEAR(self->dict);
-}
-
-
-/*
- * _BufferedIOMixin methods
- * This is not a class, just a collection of methods that will be reused
- * by BufferedReader and BufferedWriter
- */
-
-/* Positioning */
-
-static PyObject*
-BufferedIOMixin_truncate(BufferedObject *self, PyObject *args)
-{
- PyObject *pos = Py_None;
- PyObject *res;
-
- if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
- return NULL;
- }
-
- /* Flush the stream. We're mixing buffered I/O with lower-level I/O,
- * and a flush may be necessary to synch both views of the current
- * file state.
- */
- res = PyObject_CallMethod(self->raw, "flush", NULL);
- if (res == NULL)
- return NULL;
- Py_DECREF(res);
-
- if (pos == Py_None)
- pos = PyObject_CallMethod(self->raw, "tell", NULL);
- else
- Py_INCREF(pos);
-
- /* XXX: Should seek() be used, instead of passing the position
- * XXX directly to truncate?
- */
- res = PyObject_CallMethod(self->raw, "truncate", "O", pos);
- Py_DECREF(pos);
-
- return res;
-}
-
-/* Flush and close */
-
-static PyObject*
-BufferedIOMixin_flush(BufferedObject *self, PyObject *args)
-{
- return PyObject_CallMethod(self->raw, "flush", NULL);
-}
-
-static int
-BufferedIOMixin_closed(BufferedObject *self)
-{
- int closed;
- PyObject *res = PyObject_GetAttrString(self->raw, "closed");
- if (res == NULL)
- return 0;
- closed = PyObject_IsTrue(res);
- Py_DECREF(res);
- return closed;
-}
-
-static PyObject *
-BufferedIOMixin_closed_get(BufferedObject *self, void *context)
-{
- return PyObject_GetAttrString(self->raw, "closed");
-}
-
-
-static PyObject*
-BufferedIOMixin_close(BufferedObject *self, PyObject *args)
-{
- PyObject *res;
-
- if (BufferedIOMixin_closed(self))
- Py_RETURN_NONE;
-
- res = PyObject_CallMethod((PyObject *)self, "flush", NULL);
- if (res == NULL) {
- /* If flush() fails, just give up */
- if (PyErr_ExceptionMatches(PyExc_IOError))
- PyErr_Clear();
- else
- return NULL;
- }
-
- return PyObject_CallMethod(self->raw, "close", NULL);
-}
-
-/* Inquiries */
-
-static PyObject*
-BufferedIOMixin_seekable(BufferedObject *self, PyObject *args)
-{
- return PyObject_CallMethod(self->raw, "seekable", NULL);
-}
-
-static PyObject*
-BufferedIOMixin_readable(BufferedObject *self, PyObject *args)
-{
- return PyObject_CallMethod(self->raw, "readable", NULL);
-}
-
-static PyObject*
-BufferedIOMixin_writable(BufferedObject *self, PyObject *args)
-{
- return PyObject_CallMethod(self->raw, "writable", NULL);
-}
-
-/* Lower-level APIs */
-
-static PyObject*
-BufferedIOMixin_fileno(BufferedObject *self, PyObject *args)
-{
- return PyObject_CallMethod(self->raw, "fileno", NULL);
-}
-
-static PyObject*
-BufferedIOMixin_isatty(BufferedObject *self, PyObject *args)
-{
- return PyObject_CallMethod(self->raw, "isatty", NULL);
-}
-
-
-/*
- * class BufferedReader
- */
-
-PyDoc_STRVAR(BufferedReader_doc,
- "Create a new buffered reader using the given readable raw IO object.");
-
-static int _BufferedReader_reset_read_buf(BufferedObject *self)
-{
- PyObject *oldbuf = self->read_buf;
-
- self->read_buf = PyBytes_FromStringAndSize(NULL, 0);
- self->read_pos = 0;
-
- Py_XDECREF(oldbuf);
-
- if (self->read_buf == NULL)
- return -1;
-
- return 0;
-}
-
-static int
-BufferedReader_init(BufferedObject *self, PyObject *args, PyObject *kwds)
-{
- char *kwlist[] = {"raw", "buffer_size", NULL};
- Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
- PyObject *raw;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedReader", kwlist,
- &raw, &buffer_size)) {
- return -1;
- }
-
- if (IOBase_checkReadable(raw, NULL) == NULL)
- return -1;
-
- Py_INCREF(raw);
- self->raw = raw;
-
- self->buffer_size = buffer_size;
- self->read_buf = NULL;
-
- if( _BufferedReader_reset_read_buf(self) < 0)
- return -1;
-
- self->read_lock = PyThread_allocate_lock();
- if (self->read_lock == NULL) {
- PyErr_SetString(PyExc_RuntimeError, "can't allocate read lock");
- return -1;
- }
-
- return 0;
-}
-
-static PyObject *
-_BufferedReader_read_unlocked(BufferedObject *self, Py_ssize_t n)
-{
- PyObject *nodata_val = NULL;
- PyObject *empty_values = NULL;
-
- PyObject *buf = self->read_buf;
- Py_ssize_t pos = self->read_pos;
- PyObject *data, *chunks, *sep, *res;
- Py_ssize_t current_size;
-
- /* Special case for when the number of bytes to read is unspecified. */
- if (n == -1) {
- chunks = PyList_New(0);
- if (chunks == NULL)
- return NULL;
-
- Py_INCREF(buf);
- if (_BufferedReader_reset_read_buf(self) < 0)
- return NULL;
-
- /* Strip the consumed bytes */
- current_size = Py_SIZE(buf) - pos;
- data = NULL;
- if (current_size) {
- data = PyBytes_FromStringAndSize(PyBytes_AS_STRING(buf) + pos, current_size);
- if (data == NULL) {
- Py_DECREF(buf);
- Py_DECREF(chunks);
- return NULL;
- }
- Py_DECREF(buf);
- }
-
- while (1) {
- if (data) {
- if (PyList_Append(chunks, data) < 0) {
- Py_DECREF(data);
- Py_DECREF(chunks);
- return NULL;
- }
- Py_DECREF(data);
- }
-
- /* Read until EOF or until read() would block. */
- data = PyObject_CallMethod(self->raw, "read", NULL);
-
- if (data == NULL) {
- Py_DECREF(chunks);
- return NULL;
- }
-
- if (data != Py_None && !PyBytes_Check(data)) {
- Py_DECREF(data);
- Py_DECREF(chunks);
- PyErr_SetString(PyExc_TypeError, "read() should return bytes");
- return NULL;
- }
-
- if (data == Py_None || Py_SIZE(data) == 0) {
- if (current_size == 0) {
- Py_DECREF(chunks);
- return data;
- }
- else {
- Py_DECREF(data);
- sep = PyBytes_FromStringAndSize(NULL, 0);
-
- if (sep == NULL) {
- Py_DECREF(chunks);
- return NULL;
- }
- res =_PyBytes_Join(sep, chunks);
- Py_DECREF(sep);
- Py_DECREF(chunks);
-
- return res;
- }
- }
-
- current_size += Py_SIZE(data);
- }
- }
-
- /* The number of bytes to read is specified, return at most n bytes. */
-
- current_size = Py_SIZE(buf) - pos; /* Length of the available buffered data. */
- if (n <= current_size) {
- /* Fast path: the data to read is fully buffered. */
- self->read_pos += n;
- return PyBytes_FromStringAndSize(PyBytes_AS_STRING(buf) + pos, n);
- }
-
- /* Slow path: read from the stream until enough bytes are read,
- * or until an EOF occurs or until read() would block.
- */
- chunks = PyList_New(0);
- if (chunks == NULL)
- return NULL;
-
- data = NULL;
-
- if (current_size)
- data = PyBytes_FromStringAndSize(PyBytes_AS_STRING(buf) + pos, current_size);
-
- while (1) {
- Py_ssize_t wanted;
-
- if (data) {
- if (PyList_Append(chunks, data) < 0) {
- Py_DECREF(data);
- Py_DECREF(chunks);
- return NULL;
- }
- Py_DECREF(data);
- }
-
- if (current_size >= n)
- break;
-
- wanted = n;
- if (wanted < self->buffer_size)
- wanted = self->buffer_size;
-
- data = PyObject_CallMethod(self->raw, "read", "n", wanted);
-
- if (data != Py_None && !PyBytes_Check(data)) {
- Py_DECREF(data);
- Py_DECREF(chunks);
- PyErr_SetString(PyExc_TypeError, "read() should return bytes");
- return NULL;
- }
-
- if (data == Py_None || Py_SIZE(data) == 0) {
- /* EOF occurred or read() would block. */
-
- if (current_size == 0) {
- Py_DECREF(chunks);
-
- if( _BufferedReader_reset_read_buf(self) < 0) {
- Py_DECREF(data);
- return NULL;
- }
-
- return data;
- }
- else {
- Py_DECREF(data);
- break;
- }
- }
-
- current_size += Py_SIZE(data);
- }
-
- sep = PyBytes_FromStringAndSize(NULL, 0);
-
- if (sep == NULL) {
- Py_DECREF(chunks);
- return NULL;
- }
-
- res =_PyBytes_Join(sep, chunks);
- Py_DECREF(sep);
- Py_DECREF(chunks);
-
- if (Py_SIZE(res) > n) {
- /* Save the extra data in the buffer. */
- self->read_pos = 0;
- buf = self->read_buf;
- self->read_buf = PyBytes_FromStringAndSize(PyBytes_AS_STRING(res) + n, Py_SIZE(res) - n);
- Py_DECREF(buf);
- if (self->read_buf == NULL) {
- Py_DECREF(res);
- return NULL;
- }
-
- /* Truncate the result to the desired length */
- buf = PyBytes_FromStringAndSize(PyBytes_AS_STRING(res), n);
- if (buf == NULL) {
- Py_DECREF(res);
- return NULL;
- }
-
- Py_DECREF(res);
- res = buf;
- }
-
- return res;
-}
-
-static PyObject *
-BufferedReader_read(BufferedObject *self, PyObject *args)
-{
- Py_ssize_t n = -1;
- PyObject *res;
-
- if (!PyArg_ParseTuple(args, "|n:read", &n)) {
- return NULL;
- }
-
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->read_lock, 1);
- Py_END_ALLOW_THREADS
-
- res = _BufferedReader_read_unlocked(self, n);
-
- PyThread_release_lock(self->read_lock);
-
- return res;
-}
-
-static PyObject *
-_BufferedReader_peek_unlocked(BufferedObject *self, Py_ssize_t n)
-{
- Py_ssize_t have;
-
- if (n > self->buffer_size)
- n = self->buffer_size;
-
- have = Py_SIZE(self->read_buf) - self->read_pos;
-
- if (have < n) {
- Py_ssize_t to_read = self->buffer_size - have;
- PyObject *current = PyObject_CallMethod(self->raw, "read", "n", to_read);
-
- if (current == NULL)
- return NULL;
-
- if (!PyBytes_Check(current)) {
- Py_DECREF(current);
- PyErr_SetString(PyExc_TypeError, "read() should return bytes");
- return NULL;
- }
-
- if (Py_SIZE(current) > 0) {
- PyObject *oldbuf = self->read_buf;
- self->read_buf = PyBytes_FromStringAndSize(NULL, have + Py_SIZE(current));
- memcpy(PyBytes_AS_STRING(self->read_buf), PyBytes_AS_STRING(oldbuf) + self->read_pos, have);
- memcpy(PyBytes_AS_STRING(self->read_buf) + have, PyBytes_AS_STRING(current), Py_SIZE(current));
- self->read_pos = 0;
- }
- Py_DECREF(current);
- }
-
- if (self->read_pos == 0) {
- Py_INCREF(self->read_buf);
- return self->read_buf;
- }
- else {
- return PyBytes_FromStringAndSize(
- PyBytes_AS_STRING(self->read_buf) + self->read_pos,
- Py_SIZE(self->read_buf) - self->read_pos);
- }
-}
-
-static PyObject *
-BufferedReader_peek(BufferedObject *self, PyObject *args)
-{
- Py_ssize_t n = 0;
- PyObject *res;
-
- if (!PyArg_ParseTuple(args, "|n:peek", &n)) {
- return NULL;
- }
-
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->read_lock, 1);
- Py_END_ALLOW_THREADS
-
- res = _BufferedReader_peek_unlocked(self, n);
-
- PyThread_release_lock(self->read_lock);
-
- return res;
-}
-
-static PyObject *
-BufferedReader_read1(BufferedObject *self, PyObject *args)
-{
- Py_ssize_t n, have;
- PyObject *res;
-
- if (!PyArg_ParseTuple(args, "n:read1", &n)) {
- return NULL;
- }
-
- if (n <= 0)
- return PyBytes_FromStringAndSize(NULL, 0);
-
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->read_lock, 1);
- Py_END_ALLOW_THREADS
-
- res = _BufferedReader_peek_unlocked(self, 1);
- if(res == NULL)
- goto end;
- Py_DECREF(res);
-
- have = Py_SIZE(self->read_buf) - self->read_pos;
- if (n > have)
- n = have;
-
- res = _BufferedReader_read_unlocked(self, n);
-
- end:
- PyThread_release_lock(self->read_lock);
-
- return res;
-}
-
-static PyObject*
-BufferedReader_seek(BufferedObject *self, PyObject *args)
-{
- Py_ssize_t pos;
- int whence = 0;
- PyObject *res;
-
- if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &whence)) {
- return NULL;
- }
-
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->read_lock, 1);
- Py_END_ALLOW_THREADS
-
- if (whence == 1) {
- pos -= Py_SIZE(self->read_buf) - self->read_pos;
- }
-
- res = PyObject_CallMethod(self->raw, "seek", "ni", pos, whence);
- if (res == NULL)
- return NULL;
-
- if (_BufferedReader_reset_read_buf(self) < 0)
- Py_CLEAR(res);
-
- PyThread_release_lock(self->read_lock);
-
- return res;
-}
-
-static PyObject*
-BufferedReader_tell(BufferedObject *self, PyObject *args)
-{
- PyObject *op1, *op2, *res;
-
- op1 = PyObject_CallMethod(self->raw, "tell", NULL);
-
- if (op1 == NULL)
- return NULL;
-
- op2 = PyLong_FromSsize_t(Py_SIZE(self->read_buf) - self->read_pos);
- if (op2 == NULL) {
- Py_DECREF(op1);
- return NULL;
- }
-
- res = PyNumber_Subtract(op1, op2);
- Py_DECREF(op1);
- Py_DECREF(op2);
- return res;
-}
-
-static PyMethodDef BufferedReader_methods[] = {
- /* BufferedIOMixin methods */
- {"truncate", (PyCFunction)BufferedIOMixin_truncate, METH_VARARGS},
- {"flush", (PyCFunction)BufferedIOMixin_flush, METH_NOARGS},
- {"close", (PyCFunction)BufferedIOMixin_close, METH_NOARGS},
- {"seekable", (PyCFunction)BufferedIOMixin_seekable, METH_NOARGS},
- {"readable", (PyCFunction)BufferedIOMixin_readable, METH_NOARGS},
- {"writable", (PyCFunction)BufferedIOMixin_writable, METH_NOARGS},
- {"fileno", (PyCFunction)BufferedIOMixin_fileno, METH_NOARGS},
- {"isatty", (PyCFunction)BufferedIOMixin_isatty, METH_NOARGS},
-
- {"read", (PyCFunction)BufferedReader_read, METH_VARARGS},
- {"peek", (PyCFunction)BufferedReader_peek, METH_VARARGS},
- {"read1", (PyCFunction)BufferedReader_read1, METH_VARARGS},
- {"seek", (PyCFunction)BufferedReader_seek, METH_VARARGS},
- {"tell", (PyCFunction)BufferedReader_tell, METH_NOARGS},
- {NULL, NULL}
-};
-
-static PyMemberDef BufferedReader_members[] = {
- {"_name", T_OBJECT, offsetof(BufferedObject, name), 0},
- {"_mode", T_OBJECT, offsetof(BufferedObject, mode), 0},
- {NULL}
-};
-
-static PyGetSetDef BufferedReader_getset[] = {
- {"closed", (getter)BufferedIOMixin_closed_get, NULL, NULL},
- {0}
-};
-
-
-PyTypeObject BufferedReader_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "BufferedReader", /*tp_name*/
- sizeof(BufferedObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- (destructor)BufferedObject_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare */
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
- BufferedReader_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- offsetof(BufferedObject, weakreflist), /*tp_weaklistoffset*/
- 0, /* tp_iter */
- 0, /* tp_iternext */
- BufferedReader_methods, /* tp_methods */
- BufferedReader_members, /* tp_members */
- BufferedReader_getset, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- offsetof(BufferedObject, dict), /* tp_dictoffset */
- (initproc)BufferedReader_init, /* tp_init */
- 0, /* tp_alloc */
- PyType_GenericNew, /* tp_new */
-};
-
-
-/*
- * class BufferedWriter
- */
-PyDoc_STRVAR(BufferedWriter_doc,
- "A buffer for a writeable sequential RawIO object.\n"
- "\n"
- "The constructor creates a BufferedWriter for the given writeable raw\n"
- "stream. If the buffer_size is not given, it defaults to\n"
- "DEAFULT_BUFFER_SIZE. If max_buffer_size is omitted, it defaults to\n"
- "twice the buffer size.\n"
- );
-
-static int
-BufferedWriter_init(BufferedObject *self, PyObject *args, PyObject *kwds)
-{
- char *kwlist[] = {"raw", "buffer_size", "max_buffer_size", NULL};
- Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
- Py_ssize_t max_buffer_size = -1;
- PyObject *raw;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|nn:BufferedReader", kwlist,
- &raw, &buffer_size, &max_buffer_size)) {
- return -1;
- }
-
- if (IOBase_checkWritable(raw, NULL) == NULL)
- return -1;
-
- Py_INCREF(raw);
- self->raw = raw;
-
- if (max_buffer_size < 0)
- max_buffer_size = buffer_size * 2;
- self->buffer_size = buffer_size;
- self->max_buffer_size = max_buffer_size;
-
- self->write_buf = PyByteArray_FromStringAndSize(NULL, 0);
- if (self->write_buf == NULL)
- return -1;
-
- self->write_lock = PyThread_allocate_lock();
- if (self->write_lock == NULL) {
- PyErr_SetString(PyExc_RuntimeError, "can't allocate write lock");
- return -1;
- }
-
- return 0;
-}
-
-static PyObject *
-_BufferedWriter_flush_unlocked(BufferedObject *self)
-{
- Py_ssize_t written = 0;
-
- if (BufferedIOMixin_closed(self)) {
- PyErr_SetString(PyExc_ValueError, "flush of closed file");
- return NULL;
- }
-
- while (Py_SIZE(self->write_buf) > 0) {
- PyObject *slice, *res;
- Py_ssize_t w;
- PyObject *n = PyObject_CallMethod(self->raw, "write", "O", self->write_buf);
-
- if (n == NULL) {
- PyObject *type, *value, *traceback;
- PyErr_Fetch(&type, &value, &traceback);
-
- if (value == NULL ||
- !PyErr_GivenExceptionMatches(value, PyExc_BlockingIOError)) {
- PyErr_Restore(type, value, traceback);
- return NULL;
- }
-
- w = ((PyBlockingIOErrorObject *)value)->written;
-
- /* del self->write_buf[:w] */
- slice = _PySlice_FromIndices(0, w);
- if (slice == NULL)
- return NULL;
- res = PyObject_CallMethod(self->write_buf, "__delitem__", "O", slice);
- Py_DECREF(slice);
- if (res == NULL)
- return NULL;
- Py_DECREF(res);
-
- written += w;
- ((PyBlockingIOErrorObject *)value)->written = written;
-
- PyErr_Restore(type, value, traceback);
- return NULL;
- }
-
- /* del self->write_buf[:w] */
- w = PyNumber_AsSsize_t(n, PyExc_ValueError);
- Py_DECREF(n);
- if (w == -1 && PyErr_Occurred())
- return NULL;
-
- slice = _PySlice_FromIndices(0, w);
- if (slice == NULL)
- return NULL;
- res = PyObject_CallMethod(self->write_buf, "__delitem__", "O", slice);
- Py_DECREF(slice);
- if (res == NULL)
- return NULL;
- Py_DECREF(res);
-
- written += w;
- }
-
- Py_RETURN_NONE;
-}
-
-static PyObject *
-BufferedWriter_write(BufferedObject *self, PyObject *args)
-{
- PyObject *res;
- Py_buffer buf;
- Py_ssize_t before, written;
-
- if (!PyArg_ParseTuple(args, "y*:write", &buf)) {
- return NULL;
- }
-
- if (BufferedIOMixin_closed(self)) {
- PyErr_SetString(PyExc_ValueError, "write to closed file");
- PyBuffer_Release(&buf);
- return NULL;
- }
-
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->write_lock, 1);
- Py_END_ALLOW_THREADS
-
- /* XXX we can implement some more tricks to try and avoid
- * partial writes
- */
-
- if (Py_SIZE(self->write_buf) > self->buffer_size) {
- /* We're full, so let's pre-flush the buffer*/
- res = _BufferedWriter_flush_unlocked(self);
- if (res == NULL) {
- /* We can't accept anything else. */
- PyObject *type, *value, *traceback;
- PyErr_Fetch(&type, &value, &traceback);
-
- if (value != NULL &&
- PyErr_GivenExceptionMatches(value, PyExc_BlockingIOError)) {
- ((PyBlockingIOErrorObject *)value)->written = 0;
- }
-
- PyErr_Restore(type, value, traceback);
- goto fail;
- }
- }
-
- written = buf.len;
-
- before = Py_SIZE(self->write_buf);
- if (PyByteArray_Resize(self->write_buf, before + written) < 0) {
- res = NULL;
- goto fail;
- }
- memcpy(PyByteArray_AS_STRING(self->write_buf) + before, buf.buf, written);
-
- if (Py_SIZE(self->write_buf) > self->buffer_size) {
- res = _BufferedWriter_flush_unlocked(self);
- if (res == NULL) {
- PyObject *type, *value, *traceback;
- PyErr_Fetch(&type, &value, &traceback);
-
- if (value != NULL &&
- PyErr_GivenExceptionMatches(value, PyExc_BlockingIOError)) {
-
- Py_ssize_t overage =
- Py_SIZE(self->write_buf) - self->max_buffer_size;
-
- if (overage > 0) {
- /* We've hit max_buffer_size. We have to accept a
- * partial write and cut back our buffer.
- */
- if (PyByteArray_Resize(self->write_buf, self->max_buffer_size) < 0)
- goto fail;
- ((PyBlockingIOErrorObject *)value)->written = overage;
- }
- else
- {
- Py_CLEAR(type);
- Py_CLEAR(value);
- Py_CLEAR(traceback);
- goto end;
- }
- }
-
- PyErr_Restore(type, value, traceback);
- goto fail;
- }
- }
-
- end:
- res = PyLong_FromSsize_t(written);
-
- fail:
- PyThread_release_lock(self->write_lock);
- PyBuffer_Release(&buf);
- return res;
-}
-
-static PyObject *
-BufferedWriter_truncate(BufferedObject *self, PyObject *args)
-{
- PyObject *pos = Py_None;
- PyObject *res;
-
- if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
- return NULL;
- }
-
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->write_lock, 1);
- Py_END_ALLOW_THREADS
-
- res = _BufferedWriter_flush_unlocked(self);
- if (res == NULL)
- goto end;
- Py_DECREF(res);
-
- res = BufferedIOMixin_truncate(self, args);
-
- end:
- PyThread_release_lock(self->write_lock);
- return res;
-}
-
-static PyObject *
-BufferedWriter_flush(BufferedObject *self, PyObject *args)
-{
- PyObject *res;
-
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->write_lock, 1);
- Py_END_ALLOW_THREADS
-
- res = _BufferedWriter_flush_unlocked(self);
-
- PyThread_release_lock(self->write_lock);
-
- return res;
-}
-
-static PyObject *
-BufferedWriter_tell(BufferedObject *self, PyObject *args)
-{
- PyObject *op1, *op2, *res;
-
- op1 = PyObject_CallMethod(self->raw, "tell", NULL);
-
- op2 = PyLong_FromSsize_t(Py_SIZE(self->write_buf));
- if (op2 == NULL) {
- Py_DECREF(op1);
- return NULL;
- }
-
- res = PyNumber_Add(op1, op2);
- Py_DECREF(op1);
- Py_DECREF(op2);
- return res;
-}
-
-static PyObject *
-BufferedWriter_seek(BufferedObject *self, PyObject *args)
-{
- Py_ssize_t pos;
- int whence = 0;
- PyObject *res;
-
- if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &whence)) {
- return NULL;
- }
-
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->write_lock, 1);
- Py_END_ALLOW_THREADS
-
- res = _BufferedWriter_flush_unlocked(self);
- if (res == NULL)
- goto end;
-
- res = PyObject_CallMethod(self->raw, "seek", "ni", pos, whence);
-
- end:
- PyThread_release_lock(self->write_lock);
- return res;
-}
-
-static PyMethodDef BufferedWriter_methods[] = {
- /* BufferedIOMixin methods */
- {"close", (PyCFunction)BufferedIOMixin_close, METH_NOARGS},
- {"seekable", (PyCFunction)BufferedIOMixin_seekable, METH_NOARGS},
- {"readable", (PyCFunction)BufferedIOMixin_readable, METH_NOARGS},
- {"writable", (PyCFunction)BufferedIOMixin_writable, METH_NOARGS},
- {"fileno", (PyCFunction)BufferedIOMixin_fileno, METH_NOARGS},
- {"isatty", (PyCFunction)BufferedIOMixin_isatty, METH_NOARGS},
-
- {"write", (PyCFunction)BufferedWriter_write, METH_VARARGS},
- {"truncate", (PyCFunction)BufferedWriter_truncate, METH_VARARGS},
- {"flush", (PyCFunction)BufferedWriter_flush, METH_NOARGS},
- {"seek", (PyCFunction)BufferedWriter_seek, METH_VARARGS},
- {"tell", (PyCFunction)BufferedWriter_tell, METH_NOARGS},
- {NULL, NULL}
-};
-
-static PyMemberDef BufferedWriter_members[] = {
- {"_name", T_OBJECT, offsetof(BufferedObject, name), 0},
- {"_mode", T_OBJECT, offsetof(BufferedObject, mode), 0},
- {NULL}
-};
-
-static PyGetSetDef BufferedWriter_getset[] = {
- {"closed", (getter)BufferedIOMixin_closed_get, NULL, NULL},
- {0}
-};
-
-
-PyTypeObject BufferedWriter_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "BufferedWriter", /*tp_name*/
- sizeof(BufferedObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- (destructor)BufferedObject_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare */
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
- BufferedWriter_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- offsetof(BufferedObject, weakreflist), /*tp_weaklistoffset*/
- 0, /* tp_iter */
- 0, /* tp_iternext */
- BufferedWriter_methods, /* tp_methods */
- BufferedWriter_members, /* tp_members */
- BufferedWriter_getset, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- offsetof(BufferedObject, dict), /* tp_dictoffset */
- (initproc)BufferedWriter_init, /* tp_init */
- 0, /* tp_alloc */
- PyType_GenericNew, /* tp_new */
-};
-
-
-
-/*
- * BufferedRWPair
- */
-
-PyDoc_STRVAR(BufferedRWPair_doc,
- "A buffered reader and writer object together.\n"
- "\n"
- "A buffered reader object and buffered writer object put together to\n"
- "form a sequential IO object that can read and write. This is typically\n"
- "used with a socket or two-way pipe.\n"
- "\n"
- "reader and writer are RawIOBase objects that are readable and\n"
- "writeable respectively. If the buffer_size is omitted it defaults to\n"
- "DEFAULT_BUFFER_SIZE. The max_buffer_size (for the buffered writer)\n"
- "defaults to twice the buffer size.\n"
- );
-
-/* XXX The usefulness of this (compared to having two separate IO objects) is
- * questionable.
- */
-
-typedef struct {
- PyObject_HEAD
- BufferedObject *reader;
- BufferedObject *writer;
-} BufferedRWPairObject;
-
-static int
-BufferedRWPair_init(BufferedRWPairObject *self, PyObject *args,
- PyObject *kwds)
-{
- PyObject *reader, *writer;
- Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
- Py_ssize_t max_buffer_size = -1;
-
- if (!PyArg_ParseTuple(args, "OO|nn:BufferedRWPair", &reader, &writer,
- &buffer_size, &max_buffer_size)) {
- return -1;
- }
-
- if (IOBase_checkReadable(reader, NULL) == NULL)
- return -1;
- if (IOBase_checkWritable(writer, NULL) == NULL)
- return -1;
-
- args = Py_BuildValue("(n)", buffer_size);
- if (args == NULL) {
- Py_CLEAR(self->reader);
- return -1;
- }
- self->reader = (BufferedObject*)PyType_GenericNew(&BufferedReader_Type, args, NULL);
- Py_DECREF(args);
- if (self->reader == NULL)
- return -1;
-
- args = Py_BuildValue("(nn)", buffer_size, max_buffer_size);
- if (args == NULL) {
- Py_CLEAR(self->reader);
- return -1;
- }
- self->writer = (BufferedObject*)PyType_GenericNew(&BufferedWriter_Type, args, NULL);
- Py_DECREF(args);
- if (self->writer == NULL) {
- Py_CLEAR(self->reader);
- return -1;
- }
- return 0;
-}
-
-static void
-BufferedRWPair_dealloc(BufferedRWPairObject *self)
-{
- Py_CLEAR(self->reader);
- Py_CLEAR(self->writer);
-}
-
-static PyObject *
-_forward_call(BufferedObject *self, const char* name, PyObject *args)
-{
- PyObject *func = PyObject_GetAttrString((PyObject*)self, name);
- PyObject *ret;
-
- if (func == NULL) {
- PyErr_SetString(PyExc_AttributeError, name);
- return NULL;
- }
-
- ret = PyObject_CallObject(func, args);
- Py_DECREF(func);
- return ret;
-}
-
-static PyObject *
-BufferedRWPair_read(BufferedRWPairObject *self, PyObject *args)
-{
- return _forward_call(self->reader, "read", args);
-}
-
-static PyObject *
-BufferedRWPair_peek(BufferedRWPairObject *self, PyObject *args)
-{
- return _forward_call(self->reader, "peek", args);
-}
-
-static PyObject *
-BufferedRWPair_read1(BufferedRWPairObject *self, PyObject *args)
-{
- return _forward_call(self->reader, "read1", args);
-}
-
-static PyObject *
-BufferedRWPair_write(BufferedRWPairObject *self, PyObject *args)
-{
- return _forward_call(self->writer, "write", args);
-}
-
-static PyObject *
-BufferedRWPair_flush(BufferedRWPairObject *self, PyObject *args)
-{
- return _forward_call(self->writer, "flush", args);
-}
-
-static PyObject *
-BufferedRWPair_readable(BufferedRWPairObject *self, PyObject *args)
-{
- return _forward_call(self->reader, "readable", args);
-}
-
-static PyObject *
-BufferedRWPair_writable(BufferedRWPairObject *self, PyObject *args)
-{
- return _forward_call(self->writer, "writable", args);
-}
-
-static PyObject *
-BufferedRWPair_close(BufferedRWPairObject *self, PyObject *args)
-{
- PyObject *ret = _forward_call(self->writer, "close", args);
- if (ret == NULL)
- return NULL;
- Py_DECREF(ret);
-
- return _forward_call(self->reader, "close", args);
-}
-
-static PyObject *
-BufferedRWPair_isatty(BufferedRWPairObject *self, PyObject *args)
-{
- PyObject *ret = _forward_call(self->writer, "isatty", args);
-
- if (ret != Py_False) {
- /* either True or exception */
- return ret;
- }
- Py_DECREF(ret);
-
- return _forward_call(self->reader, "isatty", args);
-}
-
-
-static PyMethodDef BufferedRWPair_methods[] = {
- {"read", (PyCFunction)BufferedRWPair_read, METH_VARARGS},
- {"peek", (PyCFunction)BufferedRWPair_peek, METH_VARARGS},
- {"read1", (PyCFunction)BufferedRWPair_read1, METH_VARARGS},
-
- {"write", (PyCFunction)BufferedRWPair_write, METH_VARARGS},
- {"flush", (PyCFunction)BufferedRWPair_flush, METH_NOARGS},
-
- {"readable", (PyCFunction)BufferedRWPair_readable, METH_NOARGS},
- {"writable", (PyCFunction)BufferedRWPair_writable, METH_NOARGS},
-
- {"close", (PyCFunction)BufferedRWPair_close, METH_NOARGS},
- {"isatty", (PyCFunction)BufferedRWPair_isatty, METH_NOARGS},
-
- {NULL, NULL}
-};
-
-PyTypeObject BufferedRWPair_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "BufferedRWPair", /*tp_name*/
- sizeof(BufferedRWPairObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- (destructor)BufferedRWPair_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare */
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
- BufferedRWPair_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- offsetof(BufferedObject, weakreflist), /*tp_weaklistoffset*/
- 0, /* tp_iter */
- 0, /* tp_iternext */
- BufferedRWPair_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- offsetof(BufferedObject, dict), /* tp_dictoffset */
- (initproc)BufferedRWPair_init, /* tp_init */
- 0, /* tp_alloc */
- PyType_GenericNew, /* tp_new */
-};
-
-
-
-/*
- * BufferedRandom
- */
-
-PyDoc_STRVAR(BufferedRandom_doc,
- "A buffered interface to random access streams.\n"
- "\n"
- "The constructor creates a reader and writer for a seekable stream,\n"
- "raw, given in the first argument. If the buffer_size is omitted it\n"
- "defaults to DEFAULT_BUFFER_SIZE. The max_buffer_size (for the buffered\n"
- "writer) defaults to twice the buffer size.\n"
- );
-
-static int
-BufferedRandom_init(BufferedObject *self, PyObject *args, PyObject *kwds)
-{
- char *kwlist[] = {"raw", "buffer_size", "max_buffer_size", NULL};
- Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
- Py_ssize_t max_buffer_size = -1;
- PyObject *raw;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|nn:BufferedReader", kwlist,
- &raw, &buffer_size, &max_buffer_size)) {
- return -1;
- }
-
- if (IOBase_checkSeekable(raw, NULL) == NULL)
- return -1;
- if (IOBase_checkReadable(raw, NULL) == NULL)
- return -1;
- if (IOBase_checkWritable(raw, NULL) == NULL)
- return -1;
-
- Py_INCREF(raw);
- self->raw = raw;
-
- if (max_buffer_size < 0)
- max_buffer_size = buffer_size * 2;
- self->buffer_size = buffer_size;
- self->max_buffer_size = max_buffer_size;
-
- if( _BufferedReader_reset_read_buf(self) < 0)
- return -1;
-
- self->read_lock = PyThread_allocate_lock();
- if (self->read_lock == NULL) {
- PyErr_SetString(PyExc_RuntimeError, "can't allocate read lock");
- return -1;
- }
-
- self->write_buf = PyByteArray_FromStringAndSize(NULL, 0);
- if (self->write_buf == NULL)
- return -1;
-
- self->write_lock = PyThread_allocate_lock();
- if (self->write_lock == NULL) {
- PyErr_SetString(PyExc_RuntimeError, "can't allocate write lock");
- return -1;
- }
-
- return 0;
-}
-
-static PyObject *
-BufferedRandom_tell(BufferedObject *self, PyObject *args)
-{
- if (Py_SIZE(self->write_buf))
- return BufferedWriter_tell(self, args);
- else
- return BufferedReader_tell(self, args);
-}
-
-static PyObject *
-BufferedRandom_seek(BufferedObject *self, PyObject *args)
-{
- Py_ssize_t pos;
- int whence = 0;
- PyObject *res;
-
- if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &whence)) {
- return NULL;
- }
-
- res = PyObject_CallMethod((PyObject*)self, "flush", NULL);
- if (res == NULL)
- return NULL;
-
- /* First do the raw seek, then empty the read buffer, so that
- * if the raw seek fails, we don't lose buffered data forever.
- */
-
- res = PyObject_CallMethod(self->raw, "seek", "ni", pos, whence);
- if (res == NULL)
- return NULL;
-
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->read_lock, 1);
- Py_END_ALLOW_THREADS
-
- if( _BufferedReader_reset_read_buf(self) < 0)
- Py_CLEAR(res);
-
- PyThread_release_lock(self->read_lock);
- return res;
-}
-
-static PyObject *
-BufferedRandom_truncate(BufferedObject *self, PyObject *args)
-{
- PyObject *pos = Py_None;
- PyObject *res;
-
- if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
- return NULL;
- }
-
- if (pos == Py_None)
- pos = PyObject_CallMethod(self->raw, "tell", NULL);
- else
- Py_INCREF(pos);
-
- /* Use seek to flush the read buffer. */
- res = PyObject_CallMethod((PyObject *)self, "seek", "O", pos);
- Py_DECREF(pos);
- if (res == NULL)
- return NULL;
- Py_DECREF(res);
-
- args = PyTuple_New(0);
- if (args == NULL)
- return NULL;
- res = BufferedWriter_truncate(self, args);
- Py_DECREF(args);
-
- return res;
-}
-
-static PyObject *
-BufferedRandom_read(BufferedObject *self, PyObject *args)
-{
- Py_ssize_t n = -1;
- PyObject *res;
-
- if (!PyArg_ParseTuple(args, "|n:read", &n)) {
- return NULL;
- }
-
- res = BufferedWriter_flush(self, Py_None);
- if (res == NULL)
- return NULL;
-
- return BufferedReader_read(self, args);
-}
-
-static PyObject *
-BufferedRandom_readinto(BufferedObject *self, PyObject *args)
-{
- PyObject *res;
-
- res = BufferedWriter_flush(self, Py_None);
- if (res == NULL)
- return NULL;
- Py_DECREF(res);
-
- return BufferedIOBase_readinto((PyObject *)self, args);
-}
-
-static PyObject *
-BufferedRandom_peek(BufferedObject *self, PyObject *args)
-{
- PyObject *res = BufferedWriter_flush(self, Py_None);
- if (res == NULL)
- return NULL;
- Py_DECREF(res);
-
- return BufferedReader_peek(self, args);
-}
-
-static PyObject *
-BufferedRandom_read1(BufferedObject *self, PyObject *args)
-{
- PyObject *res = BufferedWriter_flush(self, Py_None);
- if (res == NULL)
- return NULL;
- Py_DECREF(res);
-
- return BufferedReader_read1(self, args);
-}
-
-static PyObject *
-BufferedRandom_write(BufferedObject *self, PyObject *args)
-{
- if (Py_SIZE(self->read_buf) > 0) {
- PyObject *res;
- /* Undo readahead */
-
- Py_BEGIN_ALLOW_THREADS
- PyThread_acquire_lock(self->read_lock, 1);
- Py_END_ALLOW_THREADS
-
- res = PyObject_CallMethod(self->raw, "seek", "ni",
- self->read_pos - Py_SIZE(self->read_buf), 1);
- Py_XDECREF(res);
- if (res != NULL) {
- if( _BufferedReader_reset_read_buf(self) < 0)
- res = NULL;
- }
-
- PyThread_release_lock(self->read_lock);
-
- if (res == NULL)
- return NULL;
- }
-
- return BufferedWriter_write(self, args);
-}
-
-
-static PyMethodDef BufferedRandom_methods[] = {
- /* BufferedIOMixin methods */
- {"close", (PyCFunction)BufferedIOMixin_close, METH_NOARGS},
- {"seekable", (PyCFunction)BufferedIOMixin_seekable, METH_NOARGS},
- {"readable", (PyCFunction)BufferedIOMixin_readable, METH_NOARGS},
- {"writable", (PyCFunction)BufferedIOMixin_writable, METH_NOARGS},
- {"fileno", (PyCFunction)BufferedIOMixin_fileno, METH_NOARGS},
- {"isatty", (PyCFunction)BufferedIOMixin_isatty, METH_NOARGS},
-
- {"flush", (PyCFunction)BufferedWriter_flush, METH_NOARGS},
-
- {"seek", (PyCFunction)BufferedRandom_seek, METH_VARARGS},
- {"tell", (PyCFunction)BufferedRandom_tell, METH_NOARGS},
- {"truncate", (PyCFunction)BufferedRandom_truncate, METH_VARARGS},
- {"read", (PyCFunction)BufferedRandom_read, METH_VARARGS},
- {"readinto", (PyCFunction)BufferedRandom_readinto, METH_VARARGS},
- {"peek", (PyCFunction)BufferedRandom_peek, METH_VARARGS},
- {"read1", (PyCFunction)BufferedRandom_read1, METH_VARARGS},
- {"write", (PyCFunction)BufferedRandom_write, METH_VARARGS},
- {NULL, NULL}
-};
-
-static PyMemberDef BufferedRandom_members[] = {
- {"_name", T_OBJECT, offsetof(BufferedObject, name), 0},
- {"_mode", T_OBJECT, offsetof(BufferedObject, mode), 0},
- {NULL}
-};
-
-static PyGetSetDef BufferedRandom_getset[] = {
- {"closed", (getter)BufferedIOMixin_closed_get, NULL, NULL},
- {0}
-};
-
-
-PyTypeObject BufferedRandom_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "BufferedRandom", /*tp_name*/
- sizeof(BufferedObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- (destructor)BufferedObject_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare */
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
- BufferedRandom_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- offsetof(BufferedObject, weakreflist), /*tp_weaklistoffset*/
- 0, /* tp_iter */
- 0, /* tp_iternext */
- BufferedRandom_methods, /* tp_methods */
- BufferedRandom_members, /* tp_members */
- BufferedRandom_getset, /* tp_getset */
- 0, /* tp_base */
- 0, /*tp_dict*/
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- offsetof(BufferedObject, dict), /*tp_dictoffset*/
- (initproc)BufferedRandom_init, /* tp_init */
- 0, /* tp_alloc */
- PyType_GenericNew, /* tp_new */
-};
-
/*
* Module definition
*/
@@ -2948,13 +545,13 @@
goto fail;
/* UnsupportedOperation inherits from ValueError and IOError */
- PyExc_UnsupportedOperation = PyObject_CallFunction(
+ PyIOExc_UnsupportedOperation = PyObject_CallFunction(
(PyObject*)&PyType_Type, "s(OO){}",
"UnsupportedOperation", PyExc_ValueError, PyExc_IOError);
- if (PyExc_UnsupportedOperation == NULL)
+ if (PyIOExc_UnsupportedOperation == NULL)
goto fail;
PyModule_AddObject(m, "UnsupportedOperation",
- PyExc_UnsupportedOperation);
+ PyIOExc_UnsupportedOperation);
/* BlockingIOError */
base = (PyTypeObject*)PyExc_IOError;
@@ -2965,65 +562,65 @@
PyModule_AddObject(m, "BlockingIOError",
(PyObject *)&_PyExc_BlockingIOError);
- if (PyType_Ready(&_IOBase_Type) < 0)
+ if (PyType_Ready(&PyIOBase_Type) < 0)
goto fail;
- Py_INCREF(&_IOBase_Type);
+ Py_INCREF(&PyIOBase_Type);
PyModule_AddObject(m, "IOBase",
- (PyObject *)&_IOBase_Type);
+ (PyObject *)&PyIOBase_Type);
- if (PyType_Ready(&_RawIOBase_Type) < 0)
+ if (PyType_Ready(&PyRawIOBase_Type) < 0)
goto fail;
- Py_INCREF(&_RawIOBase_Type);
+ Py_INCREF(&PyRawIOBase_Type);
PyModule_AddObject(m, "RawIOBase",
- (PyObject *)&_RawIOBase_Type);
+ (PyObject *)&PyRawIOBase_Type);
/* FileIO */
- PyFileIO_Type.tp_base = &_RawIOBase_Type;
+ PyFileIO_Type.tp_base = &PyRawIOBase_Type;
if (PyType_Ready(&PyFileIO_Type) < 0)
goto fail;
Py_INCREF(&PyFileIO_Type);
PyModule_AddObject(m, "FileIO", (PyObject *) &PyFileIO_Type);
/* BufferedIOBase */
- if (PyType_Ready(&_BufferedIOBase_Type) < 0)
+ if (PyType_Ready(&PyBufferedIOBase_Type) < 0)
goto fail;
- Py_INCREF(&_BufferedIOBase_Type);
- PyModule_AddObject(m, "BufferedIOBase", (PyObject *) &_BufferedIOBase_Type);
+ Py_INCREF(&PyBufferedIOBase_Type);
+ PyModule_AddObject(m, "BufferedIOBase", (PyObject *) &PyBufferedIOBase_Type);
/* BytesIO */
- PyBytesIO_Type.tp_base = &_BufferedIOBase_Type;
+ PyBytesIO_Type.tp_base = &PyBufferedIOBase_Type;
if (PyType_Ready(&PyBytesIO_Type) < 0)
goto fail;
Py_INCREF(&PyBytesIO_Type);
PyModule_AddObject(m, "BytesIO", (PyObject *) &PyBytesIO_Type);
/* BufferedReader */
- BufferedReader_Type.tp_base = &_BufferedIOBase_Type;
- if (PyType_Ready(&BufferedReader_Type) < 0)
+ PyBufferedReader_Type.tp_base = &PyBufferedIOBase_Type;
+ if (PyType_Ready(&PyBufferedReader_Type) < 0)
goto fail;
- Py_INCREF(&BufferedReader_Type);
- PyModule_AddObject(m, "BufferedReader", (PyObject *) &BufferedReader_Type);
+ Py_INCREF(&PyBufferedReader_Type);
+ PyModule_AddObject(m, "BufferedReader", (PyObject *) &PyBufferedReader_Type);
/* BufferedWriter */
- BufferedWriter_Type.tp_base = &_BufferedIOBase_Type;
- if (PyType_Ready(&BufferedWriter_Type) < 0)
+ PyBufferedWriter_Type.tp_base = &PyBufferedIOBase_Type;
+ if (PyType_Ready(&PyBufferedWriter_Type) < 0)
goto fail;
- Py_INCREF(&BufferedWriter_Type);
- PyModule_AddObject(m, "BufferedWriter", (PyObject *) &BufferedWriter_Type);
+ Py_INCREF(&PyBufferedWriter_Type);
+ PyModule_AddObject(m, "BufferedWriter", (PyObject *) &PyBufferedWriter_Type);
/* BufferedRWPair */
- BufferedRWPair_Type.tp_base = &_BufferedIOBase_Type;
- if (PyType_Ready(&BufferedRWPair_Type) < 0)
+ PyBufferedRWPair_Type.tp_base = &PyBufferedIOBase_Type;
+ if (PyType_Ready(&PyBufferedRWPair_Type) < 0)
goto fail;
- Py_INCREF(&BufferedRWPair_Type);
- PyModule_AddObject(m, "BufferedRWPair", (PyObject *) &BufferedRWPair_Type);
+ Py_INCREF(&PyBufferedRWPair_Type);
+ PyModule_AddObject(m, "BufferedRWPair", (PyObject *) &PyBufferedRWPair_Type);
/* BufferedRandom */
- BufferedRandom_Type.tp_base = &_BufferedIOBase_Type;
- if (PyType_Ready(&BufferedRandom_Type) < 0)
+ PyBufferedRandom_Type.tp_base = &PyBufferedIOBase_Type;
+ if (PyType_Ready(&PyBufferedRandom_Type) < 0)
goto fail;
- Py_INCREF(&BufferedRandom_Type);
- PyModule_AddObject(m, "BufferedRandom", (PyObject *) &BufferedRandom_Type);
+ Py_INCREF(&PyBufferedRandom_Type);
+ PyModule_AddObject(m, "BufferedRandom", (PyObject *) &PyBufferedRandom_Type);
return m;
More information about the Python-checkins
mailing list