17eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/*
27eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    An implementation of Buffered I/O as defined by PEP 3116 - "New I/O"
37eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
47eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Classes defined here: BufferedIOBase, BufferedReader, BufferedWriter,
57eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    BufferedRandom.
67eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
77eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Written by Amaury Forgeot d'Arc and Antoine Pitrou
87eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel*/
97eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define PY_SSIZE_T_CLEAN
117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#include "Python.h"
127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#include "structmember.h"
137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#include "pythread.h"
147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#include "_iomodule.h"
157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/*
177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel * BufferedIOBase class, inherits from IOBase.
187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel */
197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(bufferediobase_doc,
207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Base class for buffered IO objects.\n"
217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "The main difference with RawIOBase is that the read() method\n"
237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "supports omitting the size argument, and does not have a default\n"
247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "implementation that defers to readinto().\n"
257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "In addition, read(), readinto() and write() may raise\n"
277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "BlockingIOError if the underlying raw stream is in non-blocking\n"
287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "mode and not ready; unlike their raw counterparts, they will never\n"
297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "return None.\n"
307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "A typical implementation should not inherit from a RawIOBase\n"
327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "implementation, but wrap one.\n"
337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    );
347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferediobase_readinto(PyObject *self, PyObject *args)
377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_buffer buf;
397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t len;
407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *data;
417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTuple(args, "w*:readinto", &buf)) {
437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    data = PyObject_CallMethod(self, "read", "n", buf.len);
477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (data == NULL)
487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto error;
497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyBytes_Check(data)) {
517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(data);
527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_TypeError, "read() should return bytes");
537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto error;
547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    len = Py_SIZE(data);
577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    memcpy(buf.buf, PyBytes_AS_STRING(data), len);
587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyBuffer_Release(&buf);
607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(data);
617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyLong_FromSsize_t(len);
637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel  error:
657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyBuffer_Release(&buf);
667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return NULL;
677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferediobase_unsupported(const char *message)
717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyErr_SetString(_PyIO_unsupported_operation, message);
737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return NULL;
747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(bufferediobase_detach_doc,
777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Disconnect this buffer from its underlying raw stream and return it.\n"
787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "After the raw stream has been detached, the buffer is in an unusable\n"
807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "state.\n");
817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferediobase_detach(PyObject *self)
847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return bufferediobase_unsupported("detach");
867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(bufferediobase_read_doc,
897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Read and return up to n bytes.\n"
907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "If the argument is omitted, None, or negative, reads and\n"
927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "returns all data until EOF.\n"
937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "If the argument is positive, and the underlying raw stream is\n"
957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "not 'interactive', multiple raw reads may be issued to satisfy\n"
967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "the byte count (unless EOF is reached first).  But for\n"
977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "interactive raw streams (as well as sockets and pipes), at most\n"
987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "one raw read will be issued, and a short result does not imply\n"
997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "that EOF is imminent.\n"
1007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
1017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Returns an empty bytes object on EOF.\n"
1027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
1037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Returns None if the underlying raw stream was open in non-blocking\n"
1047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "mode and no data is available at the moment.\n");
1057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
1077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferediobase_read(PyObject *self, PyObject *args)
1087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
1097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return bufferediobase_unsupported("read");
1107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
1117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(bufferediobase_read1_doc,
1137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Read and return up to n bytes, with at most one read() call\n"
1147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "to the underlying raw stream. A short result does not imply\n"
1157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "that EOF is imminent.\n"
1167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
1177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Returns an empty bytes object on EOF.\n");
1187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
1207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferediobase_read1(PyObject *self, PyObject *args)
1217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
1227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return bufferediobase_unsupported("read1");
1237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
1247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(bufferediobase_write_doc,
1267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Write the given buffer to the IO stream.\n"
1277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
1287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Returns the number of bytes written, which is never less than\n"
1297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "len(b).\n"
1307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
1317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Raises BlockingIOError if the buffer is full and the\n"
1327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "underlying raw stream cannot accept more data at the moment.\n");
1337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
1357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferediobase_write(PyObject *self, PyObject *args)
1367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
1377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return bufferediobase_unsupported("write");
1387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
1397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyMethodDef bufferediobase_methods[] = {
1427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"detach", (PyCFunction)bufferediobase_detach, METH_NOARGS, bufferediobase_detach_doc},
1437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"read", bufferediobase_read, METH_VARARGS, bufferediobase_read_doc},
1447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"read1", bufferediobase_read1, METH_VARARGS, bufferediobase_read1_doc},
1457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"readinto", bufferediobase_readinto, METH_VARARGS, NULL},
1467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"write", bufferediobase_write, METH_VARARGS, bufferediobase_write_doc},
1477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL, NULL}
1487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
1497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyTypeObject PyBufferedIOBase_Type = {
1517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyVarObject_HEAD_INIT(NULL, 0)
1527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "_io._BufferedIOBase",      /*tp_name*/
1537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_basicsize*/
1547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_itemsize*/
1557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_dealloc*/
1567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_print*/
1577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_getattr*/
1587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_setattr*/
1597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_compare */
1607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_repr*/
1617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_number*/
1627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_sequence*/
1637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_mapping*/
1647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_hash */
1657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_call*/
1667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_str*/
1677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_getattro*/
1687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_setattro*/
1697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_buffer*/
1707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
1717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    bufferediobase_doc,         /* tp_doc */
1727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_traverse */
1737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_clear */
1747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_richcompare */
1757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_weaklistoffset */
1767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_iter */
1777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_iternext */
1787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    bufferediobase_methods,     /* tp_methods */
1797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_members */
1807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_getset */
1817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    &PyIOBase_Type,             /* tp_base */
1827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_dict */
1837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_descr_get */
1847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_descr_set */
1857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_dictoffset */
1867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_init */
1877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_alloc */
1887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_new */
1897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
1907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltypedef struct {
1937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject_HEAD
1947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *raw;
1967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int ok;    /* Initialized? */
1977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int detached;
1987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int readable;
1997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int writable;
2007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* True if this is a vanilla Buffered object (rather than a user derived
2027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       class) *and* the raw stream is a vanilla FileIO object. */
2037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int fast_closed_checks;
2047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Absolute position inside the raw stream (-1 if unknown). */
2067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_off_t abs_pos;
2077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* A static buffer of size `buffer_size` */
2097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char *buffer;
2107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Current logical position in the buffer. */
2117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_off_t pos;
2127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Position of the raw stream in the buffer. */
2137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_off_t raw_pos;
2147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Just after the last buffered byte in the buffer, or -1 if the buffer
2167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       isn't ready for reading. */
2177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_off_t read_end;
2187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Just after the last byte actually written */
2207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_off_t write_pos;
2217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Just after the last byte waiting to be written, or -1 if the buffer
2227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       isn't ready for writing. */
2237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_off_t write_end;
2247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#ifdef WITH_THREAD
2267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyThread_type_lock lock;
2277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    volatile long owner;
2287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#endif
2297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t buffer_size;
2317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t buffer_mask;
2327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *dict;
2347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *weakreflist;
2357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel} buffered;
2367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/*
2387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Implementation notes:
2397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    * BufferedReader, BufferedWriter and BufferedRandom try to share most
2417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel      methods (this is helped by the members `readable` and `writable`, which
2427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel      are initialized in the respective constructors)
2437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    * They also share a single buffer for reading and writing. This enables
2447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel      interleaved reads and writes without flushing. It also makes the logic
2457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel      a bit trickier to get right.
2467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    * The absolute position of the raw stream is cached, if possible, in the
2477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel      `abs_pos` member. It must be updated every time an operation is done
2487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel      on the raw stream. If not sure, it can be reinitialized by calling
2497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel      _buffered_raw_tell(), which queries the raw stream (_buffered_raw_seek()
2507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel      also does it). To read it, use RAW_TELL().
2517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    * Three helpers, _bufferedreader_raw_read, _bufferedwriter_raw_write and
2527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel      _bufferedwriter_flush_unlocked do a lot of useful housekeeping.
2537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    NOTE: we should try to maintain block alignment of reads and writes to the
2557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    raw stream (according to the buffer size), but for now it is only done
2567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    in read() and friends.
2577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel*/
2597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* These macros protect the buffered object against concurrent operations. */
2617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#ifdef WITH_THREAD
2637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
2657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_enter_buffered_busy(buffered *self)
2667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
2677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->owner == PyThread_get_thread_ident()) {
2687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *r = PyObject_Repr((PyObject *) self);
2697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (r != NULL) {
2707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_Format(PyExc_RuntimeError,
2717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         "reentrant call inside %s",
2727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         PyString_AS_STRING(r));
2737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(r);
2747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
2757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return 0;
2767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
2777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_BEGIN_ALLOW_THREADS
2787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyThread_acquire_lock(self->lock, 1);
2797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_END_ALLOW_THREADS
2807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 1;
2817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
2827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define ENTER_BUFFERED(self) \
2847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    ( (PyThread_acquire_lock(self->lock, 0) ? \
2857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       1 : _enter_buffered_busy(self)) \
2867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     && (self->owner = PyThread_get_thread_ident(), 1) )
2877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define LEAVE_BUFFERED(self) \
2897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    do { \
2907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->owner = 0; \
2917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyThread_release_lock(self->lock); \
2927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    } while(0);
2937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#else
2957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define ENTER_BUFFERED(self) 1
2967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define LEAVE_BUFFERED(self)
2977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#endif
2987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define CHECK_INITIALIZED(self) \
3007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->ok <= 0) { \
3017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (self->detached) { \
3027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_SetString(PyExc_ValueError, \
3037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                 "raw stream has been detached"); \
3047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        } else { \
3057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_SetString(PyExc_ValueError, \
3067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                "I/O operation on uninitialized object"); \
3077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        } \
3087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL; \
3097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
3107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define CHECK_INITIALIZED_INT(self) \
3127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->ok <= 0) { \
3137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (self->detached) { \
3147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_SetString(PyExc_ValueError, \
3157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                 "raw stream has been detached"); \
3167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        } else { \
3177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_SetString(PyExc_ValueError, \
3187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                "I/O operation on uninitialized object"); \
3197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        } \
3207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1; \
3217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
3227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define IS_CLOSED(self) \
3247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (self->fast_closed_checks \
3257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     ? _PyFileIO_closed(self->raw) \
3267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     : buffered_closed(self))
3277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define CHECK_CLOSED(self, error_msg) \
3297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (IS_CLOSED(self)) { \
3307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_ValueError, error_msg); \
3317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL; \
3327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
3337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define VALID_READ_BUFFER(self) \
3367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (self->readable && self->read_end != -1)
3377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define VALID_WRITE_BUFFER(self) \
3397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (self->writable && self->write_end != -1)
3407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define ADJUST_POSITION(self, _new_pos) \
3427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    do { \
3437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->pos = _new_pos; \
3447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (VALID_READ_BUFFER(self) && self->read_end < self->pos) \
3457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->read_end = self->pos; \
3467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    } while(0)
3477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define READAHEAD(self) \
3497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    ((self->readable && VALID_READ_BUFFER(self)) \
3507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        ? (self->read_end - self->pos) : 0)
3517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define RAW_OFFSET(self) \
3537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (((VALID_READ_BUFFER(self) || VALID_WRITE_BUFFER(self)) \
3547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        && self->raw_pos >= 0) ? self->raw_pos - self->pos : 0)
3557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define RAW_TELL(self) \
3577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (self->abs_pos != -1 ? self->abs_pos : _buffered_raw_tell(self))
3587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define MINUS_LAST_BLOCK(self, size) \
3607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (self->buffer_mask ? \
3617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        (size & ~self->buffer_mask) : \
3627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        (self->buffer_size * (size / self->buffer_size)))
3637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic void
3667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_dealloc(buffered *self)
3677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
3687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->ok && _PyIOBase_finalize((PyObject *) self) < 0)
3697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return;
3707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    _PyObject_GC_UNTRACK(self);
3717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->ok = 0;
3727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->weakreflist != NULL)
3737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject_ClearWeakRefs((PyObject *)self);
3747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->raw);
3757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->buffer) {
3767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyMem_Free(self->buffer);
3777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->buffer = NULL;
3787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
3797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#ifdef WITH_THREAD
3807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->lock) {
3817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyThread_free_lock(self->lock);
3827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->lock = NULL;
3837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
3847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#endif
3857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->dict);
3867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_TYPE(self)->tp_free((PyObject *)self);
3877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
3887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
3907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_sizeof(buffered *self, void *unused)
3917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
3927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t res;
3937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = sizeof(buffered);
3957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->buffer)
3967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res += self->buffer_size;
3977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyLong_FromSsize_t(res);
3987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
3997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
4017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_traverse(buffered *self, visitproc visit, void *arg)
4027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
4037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_VISIT(self->raw);
4047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_VISIT(self->dict);
4057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
4067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
4077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
4097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_clear(buffered *self)
4107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
4117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->ok && _PyIOBase_finalize((PyObject *) self) < 0)
4127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
4137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->ok = 0;
4147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->raw);
4157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->dict);
4167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
4177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
4187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/*
4207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel * _BufferedIOMixin methods
4217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel * This is not a class, just a collection of methods that will be reused
4227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel * by BufferedReader and BufferedWriter
4237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel */
4247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* Flush and close */
4267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
4287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_simple_flush(buffered *self, PyObject *args)
4297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
4307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
4317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_flush, NULL);
4327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
4337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
4357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_closed(buffered *self)
4367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
4377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int closed;
4387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res;
4397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED_INT(self)
4407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyObject_GetAttr(self->raw, _PyIO_str_closed);
4417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
4427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
4437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    closed = PyObject_IsTrue(res);
4447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
4457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return closed;
4467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
4477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
4497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_closed_get(buffered *self, void *context)
4507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
4517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
4527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_GetAttr(self->raw, _PyIO_str_closed);
4537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
4547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
4567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_close(buffered *self, PyObject *args)
4577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
4587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res = NULL, *exc = NULL, *val, *tb;
4597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int r;
4607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
4627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!ENTER_BUFFERED(self))
4637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
4647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    r = buffered_closed(self);
4667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (r < 0)
4677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto end;
4687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (r > 0) {
4697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = Py_None;
4707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_INCREF(res);
4717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto end;
4727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
4737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* flush() will most probably re-take the lock, so drop it first */
4747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    LEAVE_BUFFERED(self)
4757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL);
4767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!ENTER_BUFFERED(self))
4777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
4787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
4797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_Fetch(&exc, &val, &tb);
4807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else
4817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(res);
4827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_close, NULL);
4847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (exc != NULL) {
4867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        _PyErr_ReplaceException(exc, val, tb);
4877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_CLEAR(res);
4887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
4897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielend:
4917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    LEAVE_BUFFERED(self)
4927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return res;
4937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
4947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* detach */
4967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
4987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_detach(buffered *self, PyObject *args)
4997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
5007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *raw, *res;
5017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
5027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL);
5037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
5047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
5057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
5067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    raw = self->raw;
5077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->raw = NULL;
5087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->detached = 1;
5097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->ok = 0;
5107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return raw;
5117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
5127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* Inquiries */
5147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
5167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_seekable(buffered *self, PyObject *args)
5177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
5187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
5197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_seekable, NULL);
5207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
5217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
5237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_readable(buffered *self, PyObject *args)
5247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
5257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
5267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readable, NULL);
5277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
5287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
5307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_writable(buffered *self, PyObject *args)
5317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
5327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
5337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_writable, NULL);
5347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
5357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
5377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_name_get(buffered *self, void *context)
5387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
5397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
5407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_GetAttrString(self->raw, "name");
5417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
5427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
5447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_mode_get(buffered *self, void *context)
5457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
5467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
5477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_GetAttrString(self->raw, "mode");
5487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
5497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* Lower-level APIs */
5517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
5537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_fileno(buffered *self, PyObject *args)
5547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
5557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
5567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_fileno, NULL);
5577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
5587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
5607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_isatty(buffered *self, PyObject *args)
5617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
5627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
5637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_isatty, NULL);
5647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
5657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* Forward decls */
5687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
5697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_bufferedwriter_flush_unlocked(buffered *);
5707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic Py_ssize_t
5717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_bufferedreader_fill_buffer(buffered *self);
5727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic void
5737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_bufferedreader_reset_buf(buffered *self);
5747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic void
5757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_bufferedwriter_reset_buf(buffered *self);
5767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
5777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_bufferedreader_peek_unlocked(buffered *self, Py_ssize_t);
5787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
5797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_bufferedreader_read_all(buffered *self);
5807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
5817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_bufferedreader_read_fast(buffered *self, Py_ssize_t);
5827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
5837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_bufferedreader_read_generic(buffered *self, Py_ssize_t);
5847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/*
5877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel * Helpers
5887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel */
5897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* Sets the current error to BlockingIOError */
5917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic void
5927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_set_BlockingIOError(char *msg, Py_ssize_t written)
5937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
5947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *err;
5957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    err = PyObject_CallFunction(PyExc_BlockingIOError, "isn",
5967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                errno, msg, written);
5977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (err)
5987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetObject(PyExc_BlockingIOError, err);
5997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(err);
6007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
6017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
6027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* Returns the address of the `written` member if a BlockingIOError was
6037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel   raised, NULL otherwise. The error is always re-raised. */
6047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic Py_ssize_t *
6057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_buffered_check_blocking_error(void)
6067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
6077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *t, *v, *tb;
6087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyBlockingIOErrorObject *err;
6097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
6107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyErr_Fetch(&t, &v, &tb);
6117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (v == NULL || !PyErr_GivenExceptionMatches(v, PyExc_BlockingIOError)) {
6127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_Restore(t, v, tb);
6137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
6147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
6157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    err = (PyBlockingIOErrorObject *) v;
6167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* TODO: sanity check (err->written >= 0) */
6177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyErr_Restore(t, v, tb);
6187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return &err->written;
6197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
6207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
6217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic Py_off_t
6227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_buffered_raw_tell(buffered *self)
6237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
6247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_off_t n;
6257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res;
6267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_tell, NULL);
6277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
6287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
6297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    n = PyNumber_AsOff_t(res, PyExc_ValueError);
6307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
6317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n < 0) {
6327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (!PyErr_Occurred())
6337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_Format(PyExc_IOError,
6347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         "Raw stream returned invalid position %" PY_PRIdOFF,
6357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel			 (PY_OFF_T_COMPAT)n);
6367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
6377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
6387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->abs_pos = n;
6397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return n;
6407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
6417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
6427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic Py_off_t
6437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_buffered_raw_seek(buffered *self, Py_off_t target, int whence)
6447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
6457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res, *posobj, *whenceobj;
6467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_off_t n;
6477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
6487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    posobj = PyLong_FromOff_t(target);
6497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (posobj == NULL)
6507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
6517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    whenceobj = PyLong_FromLong(whence);
6527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (whenceobj == NULL) {
6537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(posobj);
6547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
6557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
6567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_seek,
6577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                     posobj, whenceobj, NULL);
6587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(posobj);
6597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(whenceobj);
6607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
6617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
6627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    n = PyNumber_AsOff_t(res, PyExc_ValueError);
6637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
6647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n < 0) {
6657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (!PyErr_Occurred())
6667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_Format(PyExc_IOError,
6677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         "Raw stream returned invalid position %" PY_PRIdOFF,
6687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel			 (PY_OFF_T_COMPAT)n);
6697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
6707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
6717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->abs_pos = n;
6727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return n;
6737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
6747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
6757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
6767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_buffered_init(buffered *self)
6777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
6787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t n;
6797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->buffer_size <= 0) {
6807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_ValueError,
6817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            "buffer size must be strictly positive");
6827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
6837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
6847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->buffer)
6857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyMem_Free(self->buffer);
6867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->buffer = PyMem_Malloc(self->buffer_size);
6877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->buffer == NULL) {
6887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_NoMemory();
6897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
6907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
6917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#ifdef WITH_THREAD
6927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->lock)
6937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyThread_free_lock(self->lock);
6947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->lock = PyThread_allocate_lock();
6957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->lock == NULL) {
6967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_RuntimeError, "can't allocate read lock");
6977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
6987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
6997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->owner = 0;
7007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#endif
7017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Find out whether buffer_size is a power of 2 */
7027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* XXX is this optimization useful? */
7037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    for (n = self->buffer_size - 1; n & 1; n >>= 1)
7047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        ;
7057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n == 0)
7067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->buffer_mask = self->buffer_size - 1;
7077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else
7087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->buffer_mask = 0;
7097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_buffered_raw_tell(self) == -1)
7107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_Clear();
7117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
7127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
7137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* Return 1 if an EnvironmentError with errno == EINTR is set (and then
7157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel   clears the error indicator), 0 otherwise.
7167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel   Should only be called when PyErr_Occurred() is true.
7177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel*/
7187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielint
7197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_PyIO_trap_eintr(void)
7207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
7217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    static PyObject *eintr_int = NULL;
7227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *typ, *val, *tb;
7237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyEnvironmentErrorObject *env_err;
7247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (eintr_int == NULL) {
7267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        eintr_int = PyLong_FromLong(EINTR);
7277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        assert(eintr_int != NULL);
7287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
7297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyErr_ExceptionMatches(PyExc_EnvironmentError))
7307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return 0;
7317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyErr_Fetch(&typ, &val, &tb);
7327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyErr_NormalizeException(&typ, &val, &tb);
7337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    env_err = (PyEnvironmentErrorObject *) val;
7347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    assert(env_err != NULL);
7357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (env_err->myerrno != NULL &&
7367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject_RichCompareBool(env_err->myerrno, eintr_int, Py_EQ) > 0) {
7377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(typ);
7387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(val);
7397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_XDECREF(tb);
7407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return 1;
7417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
7427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* This silences any error set by PyObject_RichCompareBool() */
7437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyErr_Restore(typ, val, tb);
7447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
7457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
7467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/*
7487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel * Shared methods and wrappers
7497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel */
7507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
7527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_flush_and_rewind_unlocked(buffered *self)
7537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
7547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res;
7557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = _bufferedwriter_flush_unlocked(self);
7577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
7587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
7597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
7607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->readable) {
7627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Rewind the raw stream so that its position corresponds to
7637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           the current logical position. */
7647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_off_t n;
7657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        n = _buffered_raw_seek(self, -RAW_OFFSET(self), 1);
7667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        _bufferedreader_reset_buf(self);
7677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (n == -1)
7687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
7697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
7707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_RETURN_NONE;
7717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
7727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
7747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_flush(buffered *self, PyObject *args)
7757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
7767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res;
7777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
7797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_CLOSED(self, "flush of closed file")
7807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!ENTER_BUFFERED(self))
7827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
7837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = buffered_flush_and_rewind_unlocked(self);
7847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    LEAVE_BUFFERED(self)
7857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return res;
7877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
7887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
7907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_peek(buffered *self, PyObject *args)
7917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
7927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t n = 0;
7937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res = NULL;
7947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
7967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTuple(args, "|n:peek", &n)) {
7977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
7987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
7997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!ENTER_BUFFERED(self))
8017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
8027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->writable) {
8047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = buffered_flush_and_rewind_unlocked(self);
8057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (res == NULL)
8067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto end;
8077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_CLEAR(res);
8087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
8097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = _bufferedreader_peek_unlocked(self, n);
8107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielend:
8127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    LEAVE_BUFFERED(self)
8137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return res;
8147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
8157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
8177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_read(buffered *self, PyObject *args)
8187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
8197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t n = -1;
8207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res;
8217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
8237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTuple(args, "|O&:read", &_PyIO_ConvertSsize_t, &n)) {
8247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
8257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
8267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n < -1) {
8277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_ValueError,
8287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        "read length must be positive or -1");
8297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
8307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
8317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_CLOSED(self, "read of closed file")
8337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n == -1) {
8357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* The number of bytes is unspecified, read until the end of stream */
8367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (!ENTER_BUFFERED(self))
8377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
8387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = _bufferedreader_read_all(self);
8397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
8407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else {
8417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = _bufferedreader_read_fast(self, n);
8427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (res != Py_None)
8437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return res;
8447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(res);
8457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (!ENTER_BUFFERED(self))
8467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
8477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = _bufferedreader_read_generic(self, n);
8487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
8497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    LEAVE_BUFFERED(self)
8517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return res;
8527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
8537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
8557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_read1(buffered *self, PyObject *args)
8567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
8577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t n, have, r;
8587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res = NULL;
8597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
8617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTuple(args, "n:read1", &n)) {
8627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
8637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
8647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n < 0) {
8667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_ValueError,
8677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        "read length must be positive");
8687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
8697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
8707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n == 0)
8717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return PyBytes_FromStringAndSize(NULL, 0);
8727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!ENTER_BUFFERED(self))
8747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
8757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Return up to n bytes.  If at least one byte is buffered, we
8777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       only return buffered bytes.  Otherwise, we do one raw read. */
8787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* XXX: this mimicks the io.py implementation but is probably wrong.
8807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       If we need to read from the raw stream, then we could actually read
8817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       all `n` bytes asked by the caller (and possibly more, so as to fill
8827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       our buffer for the next reads). */
8837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    have = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
8857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (have > 0) {
8867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (n > have)
8877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            n = have;
8887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyBytes_FromStringAndSize(self->buffer + self->pos, n);
8897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (res == NULL)
8907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto end;
8917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->pos += n;
8927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto end;
8937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
8947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->writable) {
8967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = buffered_flush_and_rewind_unlocked(self);
8977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (res == NULL)
8987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto end;
8997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(res);
9007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
9017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
9027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Fill the buffer from the raw stream, and copy it to the result. */
9037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    _bufferedreader_reset_buf(self);
9047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    r = _bufferedreader_fill_buffer(self);
9057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (r == -1)
9067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto end;
9077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (r == -2)
9087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        r = 0;
9097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n > r)
9107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        n = r;
9117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyBytes_FromStringAndSize(self->buffer, n);
9127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
9137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto end;
9147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->pos = n;
9157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
9167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielend:
9177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    LEAVE_BUFFERED(self)
9187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return res;
9197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
9207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
9217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
9227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_readinto(buffered *self, PyObject *args)
9237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
9247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
9257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
9267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* TODO: use raw.readinto() (or a direct copy from our buffer) instead! */
9277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return bufferediobase_readinto((PyObject *)self, args);
9287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
9297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
9307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
9317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_buffered_readline(buffered *self, Py_ssize_t limit)
9327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
9337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res = NULL;
9347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *chunks = NULL;
9357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t n, written = 0;
9367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    const char *start, *s, *end;
9377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
9387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_CLOSED(self, "readline of closed file")
9397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
9407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* First, try to find a line in the buffer. This can run unlocked because
9417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       the calls to the C API are simple enough that they can't trigger
9427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       any thread switch. */
9437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    n = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
9447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (limit >= 0 && n > limit)
9457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        n = limit;
9467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    start = self->buffer + self->pos;
9477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    s = memchr(start, '\n', n);
9487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (s != NULL) {
9497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyBytes_FromStringAndSize(start, s - start + 1);
9507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (res != NULL)
9517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->pos += s - start + 1;
9527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto end_unlocked;
9537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
9547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n == limit) {
9557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyBytes_FromStringAndSize(start, n);
9567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (res != NULL)
9577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->pos += n;
9587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto end_unlocked;
9597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
9607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
9617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!ENTER_BUFFERED(self))
9627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto end_unlocked;
9637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
9647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Now we try to get some more from the raw stream */
9657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    chunks = PyList_New(0);
9667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (chunks == NULL)
9677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto end;
9687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n > 0) {
9697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyBytes_FromStringAndSize(start, n);
9707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (res == NULL)
9717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto end;
9727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (PyList_Append(chunks, res) < 0) {
9737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_CLEAR(res);
9747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto end;
9757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
9767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_CLEAR(res);
9777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        written += n;
9787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->pos += n;
9797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (limit >= 0)
9807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            limit -= n;
9817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
9827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->writable) {
9837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *r = buffered_flush_and_rewind_unlocked(self);
9847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (r == NULL)
9857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto end;
9867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(r);
9877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
9887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
9897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    for (;;) {
9907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        _bufferedreader_reset_buf(self);
9917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        n = _bufferedreader_fill_buffer(self);
9927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (n == -1)
9937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto end;
9947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (n <= 0)
9957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            break;
9967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (limit >= 0 && n > limit)
9977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            n = limit;
9987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        start = self->buffer;
9997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        end = start + n;
10007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        s = start;
10017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        while (s < end) {
10027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (*s++ == '\n') {
10037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                res = PyBytes_FromStringAndSize(start, s - start);
10047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (res == NULL)
10057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    goto end;
10067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                self->pos = s - start;
10077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto found;
10087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
10097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
10107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyBytes_FromStringAndSize(start, n);
10117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (res == NULL)
10127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto end;
10137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (n == limit) {
10147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->pos = n;
10157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            break;
10167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
10177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (PyList_Append(chunks, res) < 0) {
10187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_CLEAR(res);
10197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto end;
10207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
10217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_CLEAR(res);
10227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        written += n;
10237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (limit >= 0)
10247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            limit -= n;
10257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
10267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielfound:
10277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res != NULL && PyList_Append(chunks, res) < 0) {
10287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_CLEAR(res);
10297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto end;
10307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
10317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(res);
10327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = _PyBytes_Join(_PyIO_empty_bytes, chunks);
10337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielend:
10357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    LEAVE_BUFFERED(self)
10367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielend_unlocked:
10377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(chunks);
10387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return res;
10397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
10407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
10427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_readline(buffered *self, PyObject *args)
10437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
10447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t limit = -1;
10457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
10477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTuple(args, "|O&:readline", &_PyIO_ConvertSsize_t, &limit))
10487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
10497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return _buffered_readline(self, limit);
10507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
10517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
10547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_tell(buffered *self, PyObject *args)
10557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
10567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_off_t pos;
10577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
10597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    pos = _buffered_raw_tell(self);
10607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (pos == -1)
10617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
10627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    pos -= RAW_OFFSET(self);
10637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* TODO: sanity check (pos >= 0) */
10647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyLong_FromOff_t(pos);
10657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
10667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
10687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_seek(buffered *self, PyObject *args)
10697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
10707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_off_t target, n;
10717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int whence = 0;
10727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *targetobj, *res = NULL;
10737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
10757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTuple(args, "O|i:seek", &targetobj, &whence)) {
10767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
10777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
10787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (whence < 0 || whence > 2) {
10797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_Format(PyExc_ValueError,
10807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                     "whence must be between 0 and 2, not %d", whence);
10817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
10827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
10837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_CLOSED(self, "seek of closed file")
10857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    target = PyNumber_AsOff_t(targetobj, PyExc_ValueError);
10877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (target == -1 && PyErr_Occurred())
10887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
10897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (whence != 2 && self->readable) {
10917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_off_t current, avail;
10927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Check if seeking leaves us inside the current buffer,
10937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           so as to return quickly if possible. Also, we needn't take the
10947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           lock in this fast path.
10957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           Don't know how to do that when whence == 2, though. */
10967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* NOTE: RAW_TELL() can release the GIL but the object is in a stable
10977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           state at this point. */
10987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        current = RAW_TELL(self);
10997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        avail = READAHEAD(self);
11007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (avail > 0) {
11017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_off_t offset;
11027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (whence == 0)
11037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                offset = target - (current - RAW_OFFSET(self));
11047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            else
11057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                offset = target;
11067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (offset >= -self->pos && offset <= avail) {
11077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                self->pos += offset;
11087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                return PyLong_FromOff_t(current - avail + offset);
11097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
11107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
11117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
11127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!ENTER_BUFFERED(self))
11147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
11157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Fallback: invoke raw seek() method and clear buffer */
11177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->writable) {
11187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = _bufferedwriter_flush_unlocked(self);
11197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (res == NULL)
11207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto end;
11217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_CLEAR(res);
11227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        _bufferedwriter_reset_buf(self);
11237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
11247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* TODO: align on block boundary and read buffer if needed? */
11267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (whence == 1)
11277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        target -= RAW_OFFSET(self);
11287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    n = _buffered_raw_seek(self, target, whence);
11297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n == -1)
11307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto end;
11317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->raw_pos = -1;
11327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyLong_FromOff_t(n);
11337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res != NULL && self->readable)
11347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        _bufferedreader_reset_buf(self);
11357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielend:
11377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    LEAVE_BUFFERED(self)
11387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return res;
11397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
11407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
11427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_truncate(buffered *self, PyObject *args)
11437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
11447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *pos = Py_None;
11457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res = NULL;
11467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
11487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
11497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
11507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
11517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!ENTER_BUFFERED(self))
11537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
11547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->writable) {
11567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = buffered_flush_and_rewind_unlocked(self);
11577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (res == NULL)
11587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto end;
11597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_CLEAR(res);
11607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
11617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_truncate, pos, NULL);
11627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
11637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto end;
11647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Reset cached position */
11657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_buffered_raw_tell(self) == -1)
11667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_Clear();
11677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielend:
11697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    LEAVE_BUFFERED(self)
11707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return res;
11717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
11727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
11747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_iternext(buffered *self)
11757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
11767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *line;
11777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyTypeObject *tp;
11787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self);
11807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    tp = Py_TYPE(self);
11827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (tp == &PyBufferedReader_Type ||
11837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        tp == &PyBufferedRandom_Type) {
11847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Skip method call overhead for speed */
11857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        line = _buffered_readline(self, -1);
11867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
11877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else {
11887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        line = PyObject_CallMethodObjArgs((PyObject *)self,
11897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                           _PyIO_str_readline, NULL);
11907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (line && !PyBytes_Check(line)) {
11917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_Format(PyExc_IOError,
11927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         "readline() should have returned a bytes object, "
11937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         "not '%.200s'", Py_TYPE(line)->tp_name);
11947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(line);
11957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
11967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
11977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
11987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (line == NULL)
12007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
12017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (PyBytes_GET_SIZE(line) == 0) {
12037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Reached EOF or would have blocked */
12047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(line);
12057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
12067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
12077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return line;
12097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
12107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
12127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbuffered_repr(buffered *self)
12137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
12147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *nameobj, *res;
12157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    nameobj = PyObject_GetAttrString((PyObject *) self, "name");
12177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (nameobj == NULL) {
12187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (PyErr_ExceptionMatches(PyExc_Exception))
12197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_Clear();
12207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        else
12217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
12227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyString_FromFormat("<%s>", Py_TYPE(self)->tp_name);
12237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
12247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else {
12257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *repr = PyObject_Repr(nameobj);
12267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(nameobj);
12277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (repr == NULL)
12287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
12297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyString_FromFormat("<%s name=%s>",
12307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                   Py_TYPE(self)->tp_name,
12317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                   PyString_AS_STRING(repr));
12327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(repr);
12337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
12347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return res;
12357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
12367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/*
12387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel * class BufferedReader
12397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel */
12407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(bufferedreader_doc,
12427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel             "Create a new buffered reader using the given readable raw IO object.");
12437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic void _bufferedreader_reset_buf(buffered *self)
12457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
12467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->read_end = -1;
12477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
12487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
12507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedreader_init(buffered *self, PyObject *args, PyObject *kwds)
12517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
12527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char *kwlist[] = {"raw", "buffer_size", NULL};
12537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
12547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *raw;
12557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->ok = 0;
12577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->detached = 0;
12587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedReader", kwlist,
12607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                     &raw, &buffer_size)) {
12617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
12627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
12637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_PyIOBase_check_readable(raw, Py_True) == NULL)
12657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
12667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->raw);
12687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_INCREF(raw);
12697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->raw = raw;
12707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->buffer_size = buffer_size;
12717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->readable = 1;
12727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->writable = 0;
12737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_buffered_init(self) < 0)
12757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
12767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    _bufferedreader_reset_buf(self);
12777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->fast_closed_checks = (Py_TYPE(self) == &PyBufferedReader_Type &&
12797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                Py_TYPE(raw) == &PyFileIO_Type);
12807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->ok = 1;
12827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
12837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
12847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic Py_ssize_t
12867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_bufferedreader_raw_read(buffered *self, char *start, Py_ssize_t len)
12877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
12887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_buffer buf;
12897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *memobj, *res;
12907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t n;
12917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* NOTE: the buffer needn't be released as its object is NULL. */
12927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (PyBuffer_FillInfo(&buf, NULL, start, len, 0, PyBUF_CONTIG) == -1)
12937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
12947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    memobj = PyMemoryView_FromBuffer(&buf);
12957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (memobj == NULL)
12967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
12977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals() when EINTR
12987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       occurs so we needn't do it ourselves.
12997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       We then retry reading, ignoring the signal if no handler has
13007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       raised (see issue #10956).
13017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    */
13027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    do {
13037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readinto, memobj, NULL);
13047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    } while (res == NULL && _PyIO_trap_eintr());
13057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(memobj);
13067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
13077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
13087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == Py_None) {
13097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Non-blocking stream would have blocked. Special return code! */
13107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(res);
13117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -2;
13127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
13137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    n = PyNumber_AsSsize_t(res, PyExc_ValueError);
13147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
13157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n < 0 || n > len) {
13167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_Format(PyExc_IOError,
13177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                     "raw readinto() returned invalid length %zd "
13187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                     "(should have been between 0 and %zd)", n, len);
13197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
13207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
13217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n > 0 && self->abs_pos != -1)
13227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->abs_pos += n;
13237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return n;
13247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
13257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic Py_ssize_t
13277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_bufferedreader_fill_buffer(buffered *self)
13287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
13297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t start, len, n;
13307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (VALID_READ_BUFFER(self))
13317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        start = Py_SAFE_DOWNCAST(self->read_end, Py_off_t, Py_ssize_t);
13327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else
13337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        start = 0;
13347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    len = self->buffer_size - start;
13357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    n = _bufferedreader_raw_read(self, self->buffer + start, len);
13367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n <= 0)
13377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return n;
13387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->read_end = start + n;
13397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->raw_pos = start + n;
13407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return n;
13417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
13427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
13447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_bufferedreader_read_all(buffered *self)
13457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
13467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t current_size;
13477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res, *data = NULL;
13487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *chunks = PyList_New(0);
13497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (chunks == NULL)
13517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
13527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* First copy what we have in the current buffer. */
13547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    current_size = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
13557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (current_size) {
13567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        data = PyBytes_FromStringAndSize(
13577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->buffer + self->pos, current_size);
13587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (data == NULL) {
13597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(chunks);
13607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
13617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
13627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->pos += current_size;
13637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
13647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* We're going past the buffer's bounds, flush it */
13657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->writable) {
13667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = buffered_flush_and_rewind_unlocked(self);
13677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (res == NULL) {
13687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(chunks);
13697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
13707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
13717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_CLEAR(res);
13727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
13737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    _bufferedreader_reset_buf(self);
13747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    while (1) {
13757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (data) {
13767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (PyList_Append(chunks, data) < 0) {
13777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                Py_DECREF(data);
13787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                Py_DECREF(chunks);
13797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                return NULL;
13807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
13817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(data);
13827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
13837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Read until EOF or until read() would block. */
13857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        data = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_read, NULL);
13867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (data == NULL) {
13877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(chunks);
13887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
13897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
13907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (data != Py_None && !PyBytes_Check(data)) {
13917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(data);
13927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(chunks);
13937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_SetString(PyExc_TypeError, "read() should return bytes");
13947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
13957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
13967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (data == Py_None || PyBytes_GET_SIZE(data) == 0) {
13977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (current_size == 0) {
13987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                Py_DECREF(chunks);
13997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                return data;
14007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
14017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            else {
14027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                res = _PyBytes_Join(_PyIO_empty_bytes, chunks);
14037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                Py_DECREF(data);
14047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                Py_DECREF(chunks);
14057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                return res;
14067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
14077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
14087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        current_size += PyBytes_GET_SIZE(data);
14097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (self->abs_pos != -1)
14107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->abs_pos += PyBytes_GET_SIZE(data);
14117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
14127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
14137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* Read n bytes from the buffer if it can, otherwise return None.
14157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel   This function is simple enough that it can run unlocked. */
14167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
14177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_bufferedreader_read_fast(buffered *self, Py_ssize_t n)
14187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
14197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t current_size;
14207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    current_size = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
14227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n <= current_size) {
14237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Fast path: the data to read is fully buffered. */
14247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *res = PyBytes_FromStringAndSize(self->buffer + self->pos, n);
14257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (res != NULL)
14267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->pos += n;
14277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return res;
14287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
14297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_RETURN_NONE;
14307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
14317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* Generic read function: read from the stream until enough bytes are read,
14337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel * or until an EOF occurs or until read() would block.
14347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel */
14357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
14367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_bufferedreader_read_generic(buffered *self, Py_ssize_t n)
14377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
14387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res = NULL;
14397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t current_size, remaining, written;
14407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char *out;
14417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    current_size = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
14437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n <= current_size)
14447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return _bufferedreader_read_fast(self, n);
14457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyBytes_FromStringAndSize(NULL, n);
14477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
14487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto error;
14497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    out = PyBytes_AS_STRING(res);
14507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    remaining = n;
14517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    written = 0;
14527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (current_size > 0) {
14537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        memcpy(out, self->buffer + self->pos, current_size);
14547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        remaining -= current_size;
14557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        written += current_size;
14567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->pos += current_size;
14577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
14587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Flush the write buffer if necessary */
14597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->writable) {
14607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *r = buffered_flush_and_rewind_unlocked(self);
14617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (r == NULL)
14627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
14637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(r);
14647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
14657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    _bufferedreader_reset_buf(self);
14667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    while (remaining > 0) {
14677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* We want to read a whole block at the end into buffer.
14687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           If we had readv() we could do this in one pass. */
14697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_ssize_t r = MINUS_LAST_BLOCK(self, remaining);
14707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (r == 0)
14717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            break;
14727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        r = _bufferedreader_raw_read(self, out + written, r);
14737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (r == -1)
14747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
14757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (r == 0 || r == -2) {
14767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            /* EOF occurred or read() would block. */
14777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (r == 0 || written > 0) {
14787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (_PyBytes_Resize(&res, written))
14797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    goto error;
14807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                return res;
14817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
14827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(res);
14837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_INCREF(Py_None);
14847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return Py_None;
14857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
14867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        remaining -= r;
14877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        written += r;
14887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
14897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    assert(remaining <= self->buffer_size);
14907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->pos = 0;
14917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->raw_pos = 0;
14927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->read_end = 0;
14937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* NOTE: when the read is satisfied, we avoid issuing any additional
14947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       reads, which could block indefinitely (e.g. on a socket).
14957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       See issue #9550. */
14967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    while (remaining > 0 && self->read_end < self->buffer_size) {
14977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_ssize_t r = _bufferedreader_fill_buffer(self);
14987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (r == -1)
14997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
15007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (r == 0 || r == -2) {
15017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            /* EOF occurred or read() would block. */
15027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (r == 0 || written > 0) {
15037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (_PyBytes_Resize(&res, written))
15047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    goto error;
15057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                return res;
15067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
15077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(res);
15087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_INCREF(Py_None);
15097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return Py_None;
15107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
15117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (remaining > r) {
15127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            memcpy(out + written, self->buffer + self->pos, r);
15137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            written += r;
15147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->pos += r;
15157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            remaining -= r;
15167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
15177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        else if (remaining > 0) {
15187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            memcpy(out + written, self->buffer + self->pos, remaining);
15197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            written += remaining;
15207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->pos += remaining;
15217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            remaining = 0;
15227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
15237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (remaining == 0)
15247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            break;
15257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
15267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return res;
15287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielerror:
15307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(res);
15317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return NULL;
15327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
15337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
15357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_bufferedreader_peek_unlocked(buffered *self, Py_ssize_t n)
15367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
15377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t have, r;
15387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    have = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
15407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Constraints:
15417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       1. we don't want to advance the file position.
15427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       2. we don't want to lose block alignment, so we can't shift the buffer
15437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel          to make some place.
15447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       Therefore, we either return `have` bytes (if > 0), or a full buffer.
15457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    */
15467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (have > 0) {
15477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return PyBytes_FromStringAndSize(self->buffer + self->pos, have);
15487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
15497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Fill the buffer from the raw stream, and copy it to the result. */
15517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    _bufferedreader_reset_buf(self);
15527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    r = _bufferedreader_fill_buffer(self);
15537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (r == -1)
15547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
15557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (r == -2)
15567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        r = 0;
15577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->pos = 0;
15587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyBytes_FromStringAndSize(self->buffer, r);
15597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
15607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyMethodDef bufferedreader_methods[] = {
15627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* BufferedIOMixin methods */
15637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"detach", (PyCFunction)buffered_detach, METH_NOARGS},
15647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"flush", (PyCFunction)buffered_simple_flush, METH_NOARGS},
15657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"close", (PyCFunction)buffered_close, METH_NOARGS},
15667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS},
15677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"readable", (PyCFunction)buffered_readable, METH_NOARGS},
15687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"writable", (PyCFunction)buffered_writable, METH_NOARGS},
15697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
15707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
15717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"read", (PyCFunction)buffered_read, METH_VARARGS},
15737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"peek", (PyCFunction)buffered_peek, METH_VARARGS},
15747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"read1", (PyCFunction)buffered_read1, METH_VARARGS},
15757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"readline", (PyCFunction)buffered_readline, METH_VARARGS},
15767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"seek", (PyCFunction)buffered_seek, METH_VARARGS},
15777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"tell", (PyCFunction)buffered_tell, METH_NOARGS},
15787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS},
15797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS},
15807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL, NULL}
15817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
15827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyMemberDef bufferedreader_members[] = {
15847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"raw", T_OBJECT, offsetof(buffered, raw), READONLY},
15857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL}
15867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
15877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyGetSetDef bufferedreader_getset[] = {
15897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"closed", (getter)buffered_closed_get, NULL, NULL},
15907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"name", (getter)buffered_name_get, NULL, NULL},
15917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"mode", (getter)buffered_mode_get, NULL, NULL},
15927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL}
15937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
15947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyTypeObject PyBufferedReader_Type = {
15977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyVarObject_HEAD_INIT(NULL, 0)
15987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "_io.BufferedReader",       /*tp_name*/
15997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    sizeof(buffered),           /*tp_basicsize*/
16007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_itemsize*/
16017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (destructor)buffered_dealloc,     /*tp_dealloc*/
16027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_print*/
16037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_getattr*/
16047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_setattr*/
16057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_compare */
16067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (reprfunc)buffered_repr,    /*tp_repr*/
16077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_number*/
16087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_sequence*/
16097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_mapping*/
16107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_hash */
16117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_call*/
16127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_str*/
16137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_getattro*/
16147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_setattro*/
16157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_buffer*/
16167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
16177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
16187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    bufferedreader_doc,         /* tp_doc */
16197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (traverseproc)buffered_traverse, /* tp_traverse */
16207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (inquiry)buffered_clear,    /* tp_clear */
16217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_richcompare */
16227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    offsetof(buffered, weakreflist), /*tp_weaklistoffset*/
16237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_iter */
16247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (iternextfunc)buffered_iternext, /* tp_iternext */
16257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    bufferedreader_methods,     /* tp_methods */
16267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    bufferedreader_members,     /* tp_members */
16277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    bufferedreader_getset,      /* tp_getset */
16287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_base */
16297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_dict */
16307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_descr_get */
16317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_descr_set */
16327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    offsetof(buffered, dict), /* tp_dictoffset */
16337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (initproc)bufferedreader_init, /* tp_init */
16347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_alloc */
16357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyType_GenericNew,          /* tp_new */
16367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
16377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
16417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielcomplain_about_max_buffer_size(void)
16427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
16437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (PyErr_WarnEx(PyExc_DeprecationWarning,
16447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                     "max_buffer_size is deprecated", 1) < 0)
16457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return 0;
16467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 1;
16477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
16487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/*
16507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel * class BufferedWriter
16517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel */
16527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(bufferedwriter_doc,
16537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "A buffer for a writeable sequential RawIO object.\n"
16547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
16557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "The constructor creates a BufferedWriter for the given writeable raw\n"
16567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "stream. If the buffer_size is not given, it defaults to\n"
16577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "DEFAULT_BUFFER_SIZE. max_buffer_size isn't used anymore.\n"
16587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    );
16597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic void
16617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_bufferedwriter_reset_buf(buffered *self)
16627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
16637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->write_pos = 0;
16647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->write_end = -1;
16657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
16667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
16687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedwriter_init(buffered *self, PyObject *args, PyObject *kwds)
16697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
16707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* TODO: properly deprecate max_buffer_size */
16717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char *kwlist[] = {"raw", "buffer_size", "max_buffer_size", NULL};
16727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
16737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t max_buffer_size = -234;
16747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *raw;
16757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->ok = 0;
16777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->detached = 0;
16787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|nn:BufferedWriter", kwlist,
16807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                     &raw, &buffer_size, &max_buffer_size)) {
16817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
16827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
16837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (max_buffer_size != -234 && !complain_about_max_buffer_size())
16857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
16867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_PyIOBase_check_writable(raw, Py_True) == NULL)
16887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
16897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->raw);
16917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_INCREF(raw);
16927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->raw = raw;
16937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->readable = 0;
16947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->writable = 1;
16957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->buffer_size = buffer_size;
16977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_buffered_init(self) < 0)
16987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
16997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    _bufferedwriter_reset_buf(self);
17007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->pos = 0;
17017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
17027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->fast_closed_checks = (Py_TYPE(self) == &PyBufferedWriter_Type &&
17037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                Py_TYPE(raw) == &PyFileIO_Type);
17047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
17057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->ok = 1;
17067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
17077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
17087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
17097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic Py_ssize_t
17107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_bufferedwriter_raw_write(buffered *self, char *start, Py_ssize_t len)
17117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
17127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_buffer buf;
17137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *memobj, *res;
17147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t n;
17157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int errnum;
17167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* NOTE: the buffer needn't be released as its object is NULL. */
17177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (PyBuffer_FillInfo(&buf, NULL, start, len, 1, PyBUF_CONTIG_RO) == -1)
17187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
17197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    memobj = PyMemoryView_FromBuffer(&buf);
17207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (memobj == NULL)
17217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
17227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals() when EINTR
17237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       occurs so we needn't do it ourselves.
17247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       We then retry writing, ignoring the signal if no handler has
17257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       raised (see issue #10956).
17267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    */
17277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    do {
17287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        errno = 0;
17297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_write, memobj, NULL);
17307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        errnum = errno;
17317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    } while (res == NULL && _PyIO_trap_eintr());
17327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(memobj);
17337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
17347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
17357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == Py_None) {
17367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Non-blocking stream would have blocked. Special return code!
17377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           Being paranoid we reset errno in case it is changed by code
17387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           triggered by a decref.  errno is used by _set_BlockingIOError(). */
17397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(res);
17407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        errno = errnum;
17417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -2;
17427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
17437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    n = PyNumber_AsSsize_t(res, PyExc_ValueError);
17447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
17457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n < 0 || n > len) {
17467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_Format(PyExc_IOError,
17477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                     "raw write() returned invalid length %zd "
17487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                     "(should have been between 0 and %zd)", n, len);
17497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
17507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
17517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n > 0 && self->abs_pos != -1)
17527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->abs_pos += n;
17537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return n;
17547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
17557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
17567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* `restore_pos` is 1 if we need to restore the raw stream position at
17577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel   the end, 0 otherwise. */
17587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
17597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_bufferedwriter_flush_unlocked(buffered *self)
17607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
17617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t written = 0;
17627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_off_t n, rewind;
17637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
17647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!VALID_WRITE_BUFFER(self) || self->write_pos == self->write_end)
17657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto end;
17667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* First, rewind */
17677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    rewind = RAW_OFFSET(self) + (self->pos - self->write_pos);
17687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (rewind != 0) {
17697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        n = _buffered_raw_seek(self, -rewind, 1);
17707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (n < 0) {
17717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
17727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
17737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->raw_pos -= rewind;
17747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
17757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    while (self->write_pos < self->write_end) {
17767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        n = _bufferedwriter_raw_write(self,
17777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->buffer + self->write_pos,
17787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_SAFE_DOWNCAST(self->write_end - self->write_pos,
17797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                             Py_off_t, Py_ssize_t));
17807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (n == -1) {
17817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
17827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
17837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        else if (n == -2) {
17847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            _set_BlockingIOError("write could not complete without blocking",
17857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 0);
17867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
17877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
17887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->write_pos += n;
17897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->raw_pos = self->write_pos;
17907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        written += Py_SAFE_DOWNCAST(n, Py_off_t, Py_ssize_t);
17917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Partial writes can return successfully when interrupted by a
17927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           signal (see write(2)).  We must run signal handlers before
17937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           blocking another time, possibly indefinitely. */
17947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (PyErr_CheckSignals() < 0)
17957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
17967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
17977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
17987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    _bufferedwriter_reset_buf(self);
17997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielend:
18017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_RETURN_NONE;
18027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielerror:
18047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return NULL;
18057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
18067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
18087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedwriter_write(buffered *self, PyObject *args)
18097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
18107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res = NULL;
18117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_buffer buf;
18127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t written, avail, remaining;
18137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_off_t offset;
18147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self)
18167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTuple(args, "s*:write", &buf)) {
18177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
18187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
18197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (IS_CLOSED(self)) {
18217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_ValueError, "write to closed file");
18227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyBuffer_Release(&buf);
18237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
18247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
18257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!ENTER_BUFFERED(self)) {
18277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyBuffer_Release(&buf);
18287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
18297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
18307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Fast path: the data to write can be fully buffered. */
18327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!VALID_READ_BUFFER(self) && !VALID_WRITE_BUFFER(self)) {
18337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->pos = 0;
18347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->raw_pos = 0;
18357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
18367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    avail = Py_SAFE_DOWNCAST(self->buffer_size - self->pos, Py_off_t, Py_ssize_t);
18377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (buf.len <= avail) {
18387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        memcpy(self->buffer + self->pos, buf.buf, buf.len);
18397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (!VALID_WRITE_BUFFER(self) || self->write_pos > self->pos) {
18407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->write_pos = self->pos;
18417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
18427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        ADJUST_POSITION(self, self->pos + buf.len);
18437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (self->pos > self->write_end)
18447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->write_end = self->pos;
18457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        written = buf.len;
18467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto end;
18477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
18487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* First write the current buffer */
18507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = _bufferedwriter_flush_unlocked(self);
18517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL) {
18527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_ssize_t *w = _buffered_check_blocking_error();
18537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (w == NULL)
18547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
18557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (self->readable)
18567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            _bufferedreader_reset_buf(self);
18577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Make some place by shifting the buffer. */
18587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        assert(VALID_WRITE_BUFFER(self));
18597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        memmove(self->buffer, self->buffer + self->write_pos,
18607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                Py_SAFE_DOWNCAST(self->write_end - self->write_pos,
18617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 Py_off_t, Py_ssize_t));
18627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->write_end -= self->write_pos;
18637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->raw_pos -= self->write_pos;
18647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->pos -= self->write_pos;
18657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->write_pos = 0;
18667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        avail = Py_SAFE_DOWNCAST(self->buffer_size - self->write_end,
18677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 Py_off_t, Py_ssize_t);
18687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (buf.len <= avail) {
18697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            /* Everything can be buffered */
18707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_Clear();
18717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            memcpy(self->buffer + self->write_end, buf.buf, buf.len);
18727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->write_end += buf.len;
18737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->pos += buf.len;
18747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            written = buf.len;
18757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto end;
18767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
18777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Buffer as much as possible. */
18787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        memcpy(self->buffer + self->write_end, buf.buf, avail);
18797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->write_end += avail;
18807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->pos += avail;
18817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* XXX Modifying the existing exception e using the pointer w
18827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           will change e.characters_written but not e.args[2].
18837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           Therefore we just replace with a new error. */
18847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        _set_BlockingIOError("write could not complete without blocking",
18857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                             avail);
18867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto error;
18877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
18887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(res);
18897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Adjust the raw stream position if it is away from the logical stream
18917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       position. This happens if the read buffer has been filled but not
18927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       modified (and therefore _bufferedwriter_flush_unlocked() didn't rewind
18937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       the raw stream by itself).
18947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       Fixes issue #6629.
18957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    */
18967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    offset = RAW_OFFSET(self);
18977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (offset != 0) {
18987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (_buffered_raw_seek(self, -offset, 1) < 0)
18997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
19007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->raw_pos -= offset;
19017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
19027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Then write buf itself. At this point the buffer has been emptied. */
19047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    remaining = buf.len;
19057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    written = 0;
19067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    while (remaining > self->buffer_size) {
19077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_ssize_t n = _bufferedwriter_raw_write(
19087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self, (char *) buf.buf + written, buf.len - written);
19097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (n == -1) {
19107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
19117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        } else if (n == -2) {
19127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            /* Write failed because raw file is non-blocking */
19137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (remaining > self->buffer_size) {
19147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                /* Can't buffer everything, still buffer as much as possible */
19157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                memcpy(self->buffer,
19167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                       (char *) buf.buf + written, self->buffer_size);
19177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                self->raw_pos = 0;
19187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                ADJUST_POSITION(self, self->buffer_size);
19197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                self->write_end = self->buffer_size;
19207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                written += self->buffer_size;
19217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                _set_BlockingIOError("write could not complete without "
19227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                     "blocking", written);
19237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto error;
19247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
19257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_Clear();
19267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            break;
19277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
19287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        written += n;
19297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        remaining -= n;
19307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Partial writes can return successfully when interrupted by a
19317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           signal (see write(2)).  We must run signal handlers before
19327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           blocking another time, possibly indefinitely. */
19337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (PyErr_CheckSignals() < 0)
19347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
19357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
19367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->readable)
19377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        _bufferedreader_reset_buf(self);
19387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (remaining > 0) {
19397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        memcpy(self->buffer, (char *) buf.buf + written, remaining);
19407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        written += remaining;
19417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
19427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->write_pos = 0;
19437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* TODO: sanity check (remaining >= 0) */
19447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->write_end = remaining;
19457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    ADJUST_POSITION(self, remaining);
19467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->raw_pos = 0;
19477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielend:
19497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyLong_FromSsize_t(written);
19507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielerror:
19527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    LEAVE_BUFFERED(self)
19537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyBuffer_Release(&buf);
19547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return res;
19557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
19567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyMethodDef bufferedwriter_methods[] = {
19587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* BufferedIOMixin methods */
19597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"close", (PyCFunction)buffered_close, METH_NOARGS},
19607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"detach", (PyCFunction)buffered_detach, METH_NOARGS},
19617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS},
19627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"readable", (PyCFunction)buffered_readable, METH_NOARGS},
19637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"writable", (PyCFunction)buffered_writable, METH_NOARGS},
19647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
19657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
19667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"write", (PyCFunction)bufferedwriter_write, METH_VARARGS},
19687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS},
19697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"flush", (PyCFunction)buffered_flush, METH_NOARGS},
19707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"seek", (PyCFunction)buffered_seek, METH_VARARGS},
19717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"tell", (PyCFunction)buffered_tell, METH_NOARGS},
19727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS},
19737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL, NULL}
19747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
19757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyMemberDef bufferedwriter_members[] = {
19777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"raw", T_OBJECT, offsetof(buffered, raw), READONLY},
19787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL}
19797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
19807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyGetSetDef bufferedwriter_getset[] = {
19827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"closed", (getter)buffered_closed_get, NULL, NULL},
19837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"name", (getter)buffered_name_get, NULL, NULL},
19847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"mode", (getter)buffered_mode_get, NULL, NULL},
19857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL}
19867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
19877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyTypeObject PyBufferedWriter_Type = {
19907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyVarObject_HEAD_INIT(NULL, 0)
19917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "_io.BufferedWriter",       /*tp_name*/
19927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    sizeof(buffered),           /*tp_basicsize*/
19937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_itemsize*/
19947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (destructor)buffered_dealloc,     /*tp_dealloc*/
19957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_print*/
19967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_getattr*/
19977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_setattr*/
19987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_compare */
19997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (reprfunc)buffered_repr,    /*tp_repr*/
20007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_number*/
20017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_sequence*/
20027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_mapping*/
20037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_hash */
20047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_call*/
20057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_str*/
20067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_getattro*/
20077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_setattro*/
20087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_buffer*/
20097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
20107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        | Py_TPFLAGS_HAVE_GC,   /*tp_flags*/
20117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    bufferedwriter_doc,         /* tp_doc */
20127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (traverseproc)buffered_traverse, /* tp_traverse */
20137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (inquiry)buffered_clear,    /* tp_clear */
20147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_richcompare */
20157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    offsetof(buffered, weakreflist), /*tp_weaklistoffset*/
20167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_iter */
20177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_iternext */
20187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    bufferedwriter_methods,     /* tp_methods */
20197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    bufferedwriter_members,     /* tp_members */
20207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    bufferedwriter_getset,      /* tp_getset */
20217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_base */
20227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_dict */
20237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_descr_get */
20247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_descr_set */
20257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    offsetof(buffered, dict),   /* tp_dictoffset */
20267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (initproc)bufferedwriter_init, /* tp_init */
20277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_alloc */
20287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyType_GenericNew,          /* tp_new */
20297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
20307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/*
20347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel * BufferedRWPair
20357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel */
20367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(bufferedrwpair_doc,
20387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "A buffered reader and writer object together.\n"
20397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
20407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "A buffered reader object and buffered writer object put together to\n"
20417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "form a sequential IO object that can read and write. This is typically\n"
20427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "used with a socket or two-way pipe.\n"
20437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
20447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "reader and writer are RawIOBase objects that are readable and\n"
20457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "writeable respectively. If the buffer_size is omitted it defaults to\n"
20467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "DEFAULT_BUFFER_SIZE.\n"
20477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    );
20487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* XXX The usefulness of this (compared to having two separate IO objects) is
20507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel * questionable.
20517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel */
20527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltypedef struct {
20547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject_HEAD
20557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    buffered *reader;
20567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    buffered *writer;
20577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *dict;
20587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *weakreflist;
20597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel} rwpair;
20607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
20627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedrwpair_init(rwpair *self, PyObject *args, PyObject *kwds)
20637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
20647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *reader, *writer;
20657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
20667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t max_buffer_size = -234;
20677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTuple(args, "OO|nn:BufferedRWPair", &reader, &writer,
20697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                          &buffer_size, &max_buffer_size)) {
20707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
20717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
20727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (max_buffer_size != -234 && !complain_about_max_buffer_size())
20747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
20757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_PyIOBase_check_readable(reader, Py_True) == NULL)
20777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
20787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_PyIOBase_check_writable(writer, Py_True) == NULL)
20797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
20807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->reader = (buffered *) PyObject_CallFunction(
20827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            (PyObject *) &PyBufferedReader_Type, "On", reader, buffer_size);
20837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->reader == NULL)
20847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
20857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->writer = (buffered *) PyObject_CallFunction(
20877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            (PyObject *) &PyBufferedWriter_Type, "On", writer, buffer_size);
20887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->writer == NULL) {
20897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_CLEAR(self->reader);
20907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
20917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
20927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
20947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
20957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
20977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedrwpair_traverse(rwpair *self, visitproc visit, void *arg)
20987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
20997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_VISIT(self->dict);
21007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
21017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
21027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
21047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedrwpair_clear(rwpair *self)
21057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
21067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->reader);
21077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->writer);
21087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->dict);
21097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
21107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
21117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic void
21137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedrwpair_dealloc(rwpair *self)
21147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
21157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    _PyObject_GC_UNTRACK(self);
21167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->weakreflist != NULL)
21177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject_ClearWeakRefs((PyObject *)self);
21187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->reader);
21197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->writer);
21207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->dict);
21217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_TYPE(self)->tp_free((PyObject *) self);
21227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
21237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
21257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_forward_call(buffered *self, const char *name, PyObject *args)
21267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
21277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *func, *ret;
21287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self == NULL) {
21297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_ValueError,
21307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        "I/O operation on uninitialized object");
21317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
21327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
21337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    func = PyObject_GetAttrString((PyObject *)self, name);
21357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (func == NULL) {
21367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_AttributeError, name);
21377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
21387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
21397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    ret = PyObject_CallObject(func, args);
21417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(func);
21427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return ret;
21437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
21447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
21467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedrwpair_read(rwpair *self, PyObject *args)
21477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
21487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return _forward_call(self->reader, "read", args);
21497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
21507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
21527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedrwpair_peek(rwpair *self, PyObject *args)
21537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
21547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return _forward_call(self->reader, "peek", args);
21557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
21567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
21587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedrwpair_read1(rwpair *self, PyObject *args)
21597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
21607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return _forward_call(self->reader, "read1", args);
21617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
21627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
21647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedrwpair_readinto(rwpair *self, PyObject *args)
21657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
21667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return _forward_call(self->reader, "readinto", args);
21677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
21687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
21707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedrwpair_write(rwpair *self, PyObject *args)
21717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
21727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return _forward_call(self->writer, "write", args);
21737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
21747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
21767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedrwpair_flush(rwpair *self, PyObject *args)
21777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
21787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return _forward_call(self->writer, "flush", args);
21797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
21807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
21827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedrwpair_readable(rwpair *self, PyObject *args)
21837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
21847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return _forward_call(self->reader, "readable", args);
21857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
21867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
21887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedrwpair_writable(rwpair *self, PyObject *args)
21897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
21907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return _forward_call(self->writer, "writable", args);
21917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
21927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
21947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedrwpair_close(rwpair *self, PyObject *args)
21957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
21967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *exc = NULL, *val, *tb;
21977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *ret = _forward_call(self->writer, "close", args);
21987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (ret == NULL)
21997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_Fetch(&exc, &val, &tb);
22007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else
22017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(ret);
22027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    ret = _forward_call(self->reader, "close", args);
22037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (exc != NULL) {
22047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (ret != NULL) {
22057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_CLEAR(ret);
22067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_Restore(exc, val, tb);
22077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
22087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        else {
22097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(exc);
22107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_XDECREF(val);
22117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_XDECREF(tb);
22127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
22137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
22147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return ret;
22157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
22167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
22187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedrwpair_isatty(rwpair *self, PyObject *args)
22197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
22207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *ret = _forward_call(self->writer, "isatty", args);
22217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (ret != Py_False) {
22237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* either True or exception */
22247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return ret;
22257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
22267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(ret);
22277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return _forward_call(self->reader, "isatty", args);
22297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
22307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
22327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedrwpair_closed_get(rwpair *self, void *context)
22337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
22347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->writer == NULL) {
22357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_RuntimeError,
22367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                "the BufferedRWPair object is being garbage-collected");
22377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
22387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
22397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_GetAttr((PyObject *) self->writer, _PyIO_str_closed);
22407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
22417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyMethodDef bufferedrwpair_methods[] = {
22437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"read", (PyCFunction)bufferedrwpair_read, METH_VARARGS},
22447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"peek", (PyCFunction)bufferedrwpair_peek, METH_VARARGS},
22457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"read1", (PyCFunction)bufferedrwpair_read1, METH_VARARGS},
22467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"readinto", (PyCFunction)bufferedrwpair_readinto, METH_VARARGS},
22477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"write", (PyCFunction)bufferedrwpair_write, METH_VARARGS},
22497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"flush", (PyCFunction)bufferedrwpair_flush, METH_NOARGS},
22507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"readable", (PyCFunction)bufferedrwpair_readable, METH_NOARGS},
22527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"writable", (PyCFunction)bufferedrwpair_writable, METH_NOARGS},
22537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"close", (PyCFunction)bufferedrwpair_close, METH_NOARGS},
22557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"isatty", (PyCFunction)bufferedrwpair_isatty, METH_NOARGS},
22567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL, NULL}
22587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
22597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyGetSetDef bufferedrwpair_getset[] = {
22617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"closed", (getter)bufferedrwpair_closed_get, NULL, NULL},
22627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL}
22637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
22647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyTypeObject PyBufferedRWPair_Type = {
22667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyVarObject_HEAD_INIT(NULL, 0)
22677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "_io.BufferedRWPair",       /*tp_name*/
22687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    sizeof(rwpair),            /*tp_basicsize*/
22697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_itemsize*/
22707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (destructor)bufferedrwpair_dealloc,     /*tp_dealloc*/
22717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_print*/
22727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_getattr*/
22737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_setattr*/
22747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_compare */
22757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_repr*/
22767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_number*/
22777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_sequence*/
22787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_mapping*/
22797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_hash */
22807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_call*/
22817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_str*/
22827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_getattro*/
22837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_setattro*/
22847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_buffer*/
22857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
22867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        | Py_TPFLAGS_HAVE_GC,   /* tp_flags */
22877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    bufferedrwpair_doc,         /* tp_doc */
22887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (traverseproc)bufferedrwpair_traverse, /* tp_traverse */
22897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (inquiry)bufferedrwpair_clear, /* tp_clear */
22907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_richcompare */
22917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    offsetof(rwpair, weakreflist), /*tp_weaklistoffset*/
22927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_iter */
22937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_iternext */
22947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    bufferedrwpair_methods,     /* tp_methods */
22957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_members */
22967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    bufferedrwpair_getset,      /* tp_getset */
22977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_base */
22987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_dict */
22997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_descr_get */
23007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_descr_set */
23017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    offsetof(rwpair, dict),     /* tp_dictoffset */
23027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (initproc)bufferedrwpair_init, /* tp_init */
23037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_alloc */
23047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyType_GenericNew,          /* tp_new */
23057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
23067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/*
23107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel * BufferedRandom
23117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel */
23127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(bufferedrandom_doc,
23147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "A buffered interface to random access streams.\n"
23157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
23167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "The constructor creates a reader and writer for a seekable stream,\n"
23177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "raw, given in the first argument. If the buffer_size is omitted it\n"
23187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "defaults to DEFAULT_BUFFER_SIZE. max_buffer_size isn't used anymore.\n"
23197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    );
23207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
23227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielbufferedrandom_init(buffered *self, PyObject *args, PyObject *kwds)
23237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
23247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char *kwlist[] = {"raw", "buffer_size", "max_buffer_size", NULL};
23257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
23267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t max_buffer_size = -234;
23277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *raw;
23287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->ok = 0;
23307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->detached = 0;
23317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|nn:BufferedRandom", kwlist,
23337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                     &raw, &buffer_size, &max_buffer_size)) {
23347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
23357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
23367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (max_buffer_size != -234 && !complain_about_max_buffer_size())
23387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
23397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_PyIOBase_check_seekable(raw, Py_True) == NULL)
23417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
23427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_PyIOBase_check_readable(raw, Py_True) == NULL)
23437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
23447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_PyIOBase_check_writable(raw, Py_True) == NULL)
23457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
23467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->raw);
23487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_INCREF(raw);
23497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->raw = raw;
23507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->buffer_size = buffer_size;
23517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->readable = 1;
23527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->writable = 1;
23537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_buffered_init(self) < 0)
23557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
23567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    _bufferedreader_reset_buf(self);
23577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    _bufferedwriter_reset_buf(self);
23587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->pos = 0;
23597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->fast_closed_checks = (Py_TYPE(self) == &PyBufferedRandom_Type &&
23617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                Py_TYPE(raw) == &PyFileIO_Type);
23627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->ok = 1;
23647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
23657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
23667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyMethodDef bufferedrandom_methods[] = {
23687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* BufferedIOMixin methods */
23697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"close", (PyCFunction)buffered_close, METH_NOARGS},
23707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"detach", (PyCFunction)buffered_detach, METH_NOARGS},
23717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS},
23727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"readable", (PyCFunction)buffered_readable, METH_NOARGS},
23737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"writable", (PyCFunction)buffered_writable, METH_NOARGS},
23747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
23757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
23767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"flush", (PyCFunction)buffered_flush, METH_NOARGS},
23787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"seek", (PyCFunction)buffered_seek, METH_VARARGS},
23807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"tell", (PyCFunction)buffered_tell, METH_NOARGS},
23817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS},
23827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"read", (PyCFunction)buffered_read, METH_VARARGS},
23837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"read1", (PyCFunction)buffered_read1, METH_VARARGS},
23847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"readinto", (PyCFunction)buffered_readinto, METH_VARARGS},
23857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"readline", (PyCFunction)buffered_readline, METH_VARARGS},
23867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"peek", (PyCFunction)buffered_peek, METH_VARARGS},
23877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"write", (PyCFunction)bufferedwriter_write, METH_VARARGS},
23887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS},
23897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL, NULL}
23907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
23917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyMemberDef bufferedrandom_members[] = {
23937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"raw", T_OBJECT, offsetof(buffered, raw), READONLY},
23947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL}
23957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
23967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyGetSetDef bufferedrandom_getset[] = {
23987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"closed", (getter)buffered_closed_get, NULL, NULL},
23997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"name", (getter)buffered_name_get, NULL, NULL},
24007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"mode", (getter)buffered_mode_get, NULL, NULL},
24017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL}
24027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
24037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
24047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
24057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyTypeObject PyBufferedRandom_Type = {
24067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyVarObject_HEAD_INIT(NULL, 0)
24077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "_io.BufferedRandom",       /*tp_name*/
24087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    sizeof(buffered),           /*tp_basicsize*/
24097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_itemsize*/
24107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (destructor)buffered_dealloc,     /*tp_dealloc*/
24117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_print*/
24127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_getattr*/
24137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_setattr*/
24147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_compare */
24157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (reprfunc)buffered_repr,    /*tp_repr*/
24167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_number*/
24177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_sequence*/
24187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_mapping*/
24197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_hash */
24207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_call*/
24217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_str*/
24227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_getattro*/
24237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_setattro*/
24247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_buffer*/
24257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
24267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        | Py_TPFLAGS_HAVE_GC,   /*tp_flags*/
24277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    bufferedrandom_doc,         /* tp_doc */
24287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (traverseproc)buffered_traverse, /* tp_traverse */
24297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (inquiry)buffered_clear,    /* tp_clear */
24307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_richcompare */
24317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    offsetof(buffered, weakreflist), /*tp_weaklistoffset*/
24327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_iter */
24337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (iternextfunc)buffered_iternext, /* tp_iternext */
24347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    bufferedrandom_methods,     /* tp_methods */
24357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    bufferedrandom_members,     /* tp_members */
24367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    bufferedrandom_getset,      /* tp_getset */
24377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_base */
24387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_dict*/
24397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_descr_get */
24407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_descr_set */
24417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    offsetof(buffered, dict), /*tp_dictoffset*/
24427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (initproc)bufferedrandom_init, /* tp_init */
24437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_alloc */
24447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyType_GenericNew,          /* tp_new */
24457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
24467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2447