17eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/*
27eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    An implementation of Text I/O as defined by PEP 3116 - "New I/O"
37eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
47eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Classes defined here: TextIOBase, IncrementalNewlineDecoder, TextIOWrapper.
57eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
67eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Written by Amaury Forgeot d'Arc and Antoine Pitrou
77eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel*/
87eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
97eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define PY_SSIZE_T_CLEAN
107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#include "Python.h"
117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#include "structmember.h"
127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#include "_iomodule.h"
137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* TextIOBase */
157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(textiobase_doc,
177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Base class for text I/O.\n"
187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "This class provides a character and line based interface to stream\n"
207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "I/O. There is no readinto method because Python's character strings\n"
217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "are immutable. There is no public constructor.\n"
227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    );
237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_unsupported(const char *message)
267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyErr_SetString(_PyIO_unsupported_operation, message);
287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return NULL;
297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(textiobase_detach_doc,
327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Separate the underlying buffer from the TextIOBase and return it.\n"
337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "After the underlying buffer has been detached, the TextIO is in an\n"
357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "unusable state.\n"
367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    );
377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiobase_detach(PyObject *self)
407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return _unsupported("detach");
427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(textiobase_read_doc,
457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Read at most n characters from stream.\n"
467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Read from underlying buffer until we have n characters or we hit EOF.\n"
487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "If n is negative or omitted, read until EOF.\n"
497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    );
507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiobase_read(PyObject *self, PyObject *args)
537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return _unsupported("read");
557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(textiobase_readline_doc,
587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Read until newline or EOF.\n"
597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Returns an empty string if EOF is hit immediately.\n"
617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    );
627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiobase_readline(PyObject *self, PyObject *args)
657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return _unsupported("readline");
677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(textiobase_write_doc,
707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Write string to stream.\n"
717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Returns the number of characters written (which is always equal to\n"
727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "the length of the string).\n"
737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    );
747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiobase_write(PyObject *self, PyObject *args)
777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return _unsupported("write");
797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(textiobase_encoding_doc,
827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Encoding of the text stream.\n"
837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Subclasses should override.\n"
857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    );
867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiobase_encoding_get(PyObject *self, void *context)
897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_RETURN_NONE;
917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(textiobase_newlines_doc,
947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Line endings translated so far.\n"
957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Only line endings translated during reading are considered.\n"
977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Subclasses should override.\n"
997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    );
1007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
1027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiobase_newlines_get(PyObject *self, void *context)
1037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
1047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_RETURN_NONE;
1057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
1067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(textiobase_errors_doc,
1087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "The error setting of the decoder or encoder.\n"
1097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
1107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Subclasses should override.\n"
1117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    );
1127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
1147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiobase_errors_get(PyObject *self, void *context)
1157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
1167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_RETURN_NONE;
1177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
1187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyMethodDef textiobase_methods[] = {
1217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"detach", (PyCFunction)textiobase_detach, METH_NOARGS, textiobase_detach_doc},
1227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"read", textiobase_read, METH_VARARGS, textiobase_read_doc},
1237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"readline", textiobase_readline, METH_VARARGS, textiobase_readline_doc},
1247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"write", textiobase_write, METH_VARARGS, textiobase_write_doc},
1257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL, NULL}
1267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
1277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyGetSetDef textiobase_getset[] = {
1297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"encoding", (getter)textiobase_encoding_get, NULL, textiobase_encoding_doc},
1307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"newlines", (getter)textiobase_newlines_get, NULL, textiobase_newlines_doc},
1317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"errors", (getter)textiobase_errors_get, NULL, textiobase_errors_doc},
1327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL}
1337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
1347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyTypeObject PyTextIOBase_Type = {
1367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyVarObject_HEAD_INIT(NULL, 0)
1377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "_io._TextIOBase",          /*tp_name*/
1387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_basicsize*/
1397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_itemsize*/
1407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_dealloc*/
1417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_print*/
1427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_getattr*/
1437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_setattr*/
1447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_compare */
1457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_repr*/
1467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_number*/
1477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_sequence*/
1487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_mapping*/
1497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_hash */
1507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_call*/
1517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_str*/
1527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_getattro*/
1537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_setattro*/
1547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_buffer*/
1557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
1567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    textiobase_doc,             /* tp_doc */
1577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_traverse */
1587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_clear */
1597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_richcompare */
1607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_weaklistoffset */
1617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_iter */
1627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_iternext */
1637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    textiobase_methods,         /* tp_methods */
1647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_members */
1657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    textiobase_getset,          /* tp_getset */
1667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    &PyIOBase_Type,             /* tp_base */
1677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_dict */
1687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_descr_get */
1697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_descr_set */
1707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_dictoffset */
1717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_init */
1727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_alloc */
1737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_new */
1747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
1757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* IncrementalNewlineDecoder */
1787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(incrementalnewlinedecoder_doc,
1807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Codec used when reading a file in universal newlines mode.  It wraps\n"
1817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "another incremental decoder, translating \\r\\n and \\r into \\n.  It also\n"
1827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "records the types of newlines encountered.  When used with\n"
1837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "translate=False, it ensures that the newline sequence is returned in\n"
1847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "one piece. When used with decoder=None, it expects unicode strings as\n"
1857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "decode input and translates newlines without first invoking an external\n"
1867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "decoder.\n"
1877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    );
1887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltypedef struct {
1907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject_HEAD
1917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *decoder;
1927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *errors;
1937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    signed int pendingcr: 1;
1947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    signed int translate: 1;
1957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    unsigned int seennl: 3;
1967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel} nldecoder_object;
1977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
1987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
1997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielincrementalnewlinedecoder_init(nldecoder_object *self,
2007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                               PyObject *args, PyObject *kwds)
2017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
2027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *decoder;
2037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int translate;
2047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *errors = NULL;
2057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char *kwlist[] = {"decoder", "translate", "errors", NULL};
2067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oi|O:IncrementalNewlineDecoder",
2087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                     kwlist, &decoder, &translate, &errors))
2097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
2107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->decoder = decoder;
2127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_INCREF(decoder);
2137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (errors == NULL) {
2157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->errors = PyUnicode_FromString("strict");
2167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (self->errors == NULL)
2177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return -1;
2187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
2197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else {
2207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_INCREF(errors);
2217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->errors = errors;
2227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
2237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->translate = translate;
2257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->seennl = 0;
2267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->pendingcr = 0;
2277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
2297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
2307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic void
2327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielincrementalnewlinedecoder_dealloc(nldecoder_object *self)
2337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
2347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->decoder);
2357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->errors);
2367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_TYPE(self)->tp_free((PyObject *)self);
2377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
2387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
2407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielcheck_decoded(PyObject *decoded)
2417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
2427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (decoded == NULL)
2437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
2447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyUnicode_Check(decoded)) {
2457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_Format(PyExc_TypeError,
2467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                     "decoder should return a string result, not '%.200s'",
2477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                     Py_TYPE(decoded)->tp_name);
2487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(decoded);
2497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
2507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
2517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
2527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
2537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define SEEN_CR   1
2557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define SEEN_LF   2
2567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define SEEN_CRLF 4
2577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define SEEN_ALL (SEEN_CR | SEEN_LF | SEEN_CRLF)
2587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyObject *
2607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_PyIncrementalNewlineDecoder_decode(PyObject *_self,
2617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                    PyObject *input, int final)
2627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
2637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *output;
2647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t output_len;
2657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    nldecoder_object *self = (nldecoder_object *) _self;
2667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->decoder == NULL) {
2687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_ValueError,
2697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        "IncrementalNewlineDecoder.__init__ not called");
2707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
2717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
2727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* decode input (with the eventual \r from a previous pass) */
2747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->decoder != Py_None) {
2757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        output = PyObject_CallMethodObjArgs(self->decoder,
2767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            _PyIO_str_decode, input, final ? Py_True : Py_False, NULL);
2777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
2787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else {
2797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        output = input;
2807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_INCREF(output);
2817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
2827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (check_decoded(output) < 0)
2847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
2857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
2867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    output_len = PyUnicode_GET_SIZE(output);
2877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->pendingcr && (final || output_len > 0)) {
2887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_UNICODE *out;
2897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *modified = PyUnicode_FromUnicode(NULL, output_len + 1);
2907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (modified == NULL)
2917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
2927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        out = PyUnicode_AS_UNICODE(modified);
2937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        out[0] = '\r';
2947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        memcpy(out + 1, PyUnicode_AS_UNICODE(output),
2957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel               output_len * sizeof(Py_UNICODE));
2967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(output);
2977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        output = modified;
2987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->pendingcr = 0;
2997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        output_len++;
3007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
3017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* retain last \r even when not translating data:
3037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     * then readline() is sure to get \r\n in one pass
3047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     */
3057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!final) {
3067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (output_len > 0
3077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            && PyUnicode_AS_UNICODE(output)[output_len - 1] == '\r') {
3087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (Py_REFCNT(output) == 1) {
3107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (PyUnicode_Resize(&output, output_len - 1) < 0)
3117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    goto error;
3127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
3137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            else {
3147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                PyObject *modified = PyUnicode_FromUnicode(
3157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    PyUnicode_AS_UNICODE(output),
3167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    output_len - 1);
3177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (modified == NULL)
3187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    goto error;
3197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                Py_DECREF(output);
3207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                output = modified;
3217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
3227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->pendingcr = 1;
3237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
3247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
3257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Record which newlines are read and do newline translation if desired,
3277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       all in one pass. */
3287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {
3297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_UNICODE *in_str;
3307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_ssize_t len;
3317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        int seennl = self->seennl;
3327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        int only_lf = 0;
3337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        in_str = PyUnicode_AS_UNICODE(output);
3357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        len = PyUnicode_GET_SIZE(output);
3367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (len == 0)
3387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return output;
3397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* If, up to now, newlines are consistently \n, do a quick check
3417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           for the \r *byte* with the libc's optimized memchr.
3427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           */
3437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (seennl == SEEN_LF || seennl == 0) {
3447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            only_lf = (memchr(in_str, '\r', len * sizeof(Py_UNICODE)) == NULL);
3457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
3467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
3477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (only_lf) {
3487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            /* If not already seen, quick scan for a possible "\n" character.
3497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel               (there's nothing else to be done, even when in translation mode)
3507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            */
3517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (seennl == 0 &&
3527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                memchr(in_str, '\n', len * sizeof(Py_UNICODE)) != NULL) {
3537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                Py_UNICODE *s, *end;
3547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                s = in_str;
3557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                end = in_str + len;
3567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                for (;;) {
3577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    Py_UNICODE c;
3587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    /* Fast loop for non-control characters */
3597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    while (*s > '\n')
3607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        s++;
3617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    c = *s++;
3627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    if (c == '\n') {
3637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        seennl |= SEEN_LF;
3647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        break;
3657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    }
3667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    if (s > end)
3677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        break;
3687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                }
3697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
3707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            /* Finished: we have scanned for newlines, and none of them
3717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel               need translating */
3727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
3737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        else if (!self->translate) {
3747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_UNICODE *s, *end;
3757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            /* We have already seen all newline types, no need to scan again */
3767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (seennl == SEEN_ALL)
3777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto endscan;
3787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            s = in_str;
3797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            end = in_str + len;
3807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            for (;;) {
3817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                Py_UNICODE c;
3827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                /* Fast loop for non-control characters */
3837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                while (*s > '\r')
3847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    s++;
3857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                c = *s++;
3867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (c == '\n')
3877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    seennl |= SEEN_LF;
3887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                else if (c == '\r') {
3897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    if (*s == '\n') {
3907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        seennl |= SEEN_CRLF;
3917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        s++;
3927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    }
3937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    else
3947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        seennl |= SEEN_CR;
3957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                }
3967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (s > end)
3977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    break;
3987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (seennl == SEEN_ALL)
3997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    break;
4007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
4017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        endscan:
4027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            ;
4037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
4047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        else {
4057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyObject *translated = NULL;
4067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_UNICODE *out_str;
4077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_UNICODE *in, *out, *end;
4087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (Py_REFCNT(output) != 1) {
4097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                /* We could try to optimize this so that we only do a copy
4107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                   when there is something to translate. On the other hand,
4117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                   most decoders should only output non-shared strings, i.e.
4127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                   translation is done in place. */
4137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                translated = PyUnicode_FromUnicode(NULL, len);
4147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (translated == NULL)
4157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    goto error;
4167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                assert(Py_REFCNT(translated) == 1);
4177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                memcpy(PyUnicode_AS_UNICODE(translated),
4187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                       PyUnicode_AS_UNICODE(output),
4197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                       len * sizeof(Py_UNICODE));
4207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
4217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            else {
4227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                translated = output;
4237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
4247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            out_str = PyUnicode_AS_UNICODE(translated);
4257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            in = in_str;
4267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            out = out_str;
4277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            end = in_str + len;
4287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            for (;;) {
4297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                Py_UNICODE c;
4307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                /* Fast loop for non-control characters */
4317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                while ((c = *in++) > '\r')
4327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    *out++ = c;
4337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (c == '\n') {
4347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    *out++ = c;
4357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    seennl |= SEEN_LF;
4367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    continue;
4377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                }
4387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (c == '\r') {
4397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    if (*in == '\n') {
4407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        in++;
4417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        seennl |= SEEN_CRLF;
4427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    }
4437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    else
4447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        seennl |= SEEN_CR;
4457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    *out++ = '\n';
4467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    continue;
4477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                }
4487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (in > end)
4497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    break;
4507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                *out++ = c;
4517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
4527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (translated != output) {
4537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                Py_DECREF(output);
4547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                output = translated;
4557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
4567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (out - out_str != len) {
4577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (PyUnicode_Resize(&output, out - out_str) < 0)
4587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    goto error;
4597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
4607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
4617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->seennl |= seennl;
4627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
4637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return output;
4657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel  error:
4677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(output);
4687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return NULL;
4697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
4707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
4727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielincrementalnewlinedecoder_decode(nldecoder_object *self,
4737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 PyObject *args, PyObject *kwds)
4747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
4757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char *kwlist[] = {"input", "final", NULL};
4767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *input;
4777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int final = 0;
4787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|i:IncrementalNewlineDecoder",
4807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                     kwlist, &input, &final))
4817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
4827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return _PyIncrementalNewlineDecoder_decode((PyObject *) self, input, final);
4837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
4847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
4867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielincrementalnewlinedecoder_getstate(nldecoder_object *self, PyObject *args)
4877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
4887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *buffer;
4897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    unsigned PY_LONG_LONG flag;
4907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
4917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->decoder != Py_None) {
4927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *state = PyObject_CallMethodObjArgs(self->decoder,
4937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           _PyIO_str_getstate, NULL);
4947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (state == NULL)
4957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
4967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (!PyArg_Parse(state, "(OK)", &buffer, &flag)) {
4977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(state);
4987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
4997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
5007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_INCREF(buffer);
5017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(state);
5027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
5037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else {
5047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        buffer = PyBytes_FromString("");
5057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        flag = 0;
5067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
5077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    flag <<= 1;
5087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->pendingcr)
5097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        flag |= 1;
5107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return Py_BuildValue("NK", buffer, flag);
5117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
5127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
5147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielincrementalnewlinedecoder_setstate(nldecoder_object *self, PyObject *state)
5157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
5167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *buffer;
5177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    unsigned PY_LONG_LONG flag;
5187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_Parse(state, "(OK)", &buffer, &flag))
5207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
5217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->pendingcr = (int) flag & 1;
5237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    flag >>= 1;
5247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->decoder != Py_None)
5267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return PyObject_CallMethod(self->decoder,
5277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                   "setstate", "((OK))", buffer, flag);
5287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else
5297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_RETURN_NONE;
5307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
5317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
5337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielincrementalnewlinedecoder_reset(nldecoder_object *self, PyObject *args)
5347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
5357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->seennl = 0;
5367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->pendingcr = 0;
5377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->decoder != Py_None)
5387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return PyObject_CallMethodObjArgs(self->decoder, _PyIO_str_reset, NULL);
5397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else
5407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_RETURN_NONE;
5417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
5427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
5447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielincrementalnewlinedecoder_newlines_get(nldecoder_object *self, void *context)
5457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
5467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    switch (self->seennl) {
5477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    case SEEN_CR:
5487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return PyUnicode_FromString("\r");
5497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    case SEEN_LF:
5507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return PyUnicode_FromString("\n");
5517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    case SEEN_CRLF:
5527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return PyUnicode_FromString("\r\n");
5537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    case SEEN_CR | SEEN_LF:
5547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return Py_BuildValue("ss", "\r", "\n");
5557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    case SEEN_CR | SEEN_CRLF:
5567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return Py_BuildValue("ss", "\r", "\r\n");
5577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    case SEEN_LF | SEEN_CRLF:
5587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return Py_BuildValue("ss", "\n", "\r\n");
5597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    case SEEN_CR | SEEN_LF | SEEN_CRLF:
5607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return Py_BuildValue("sss", "\r", "\n", "\r\n");
5617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    default:
5627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_RETURN_NONE;
5637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel   }
5647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
5667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyMethodDef incrementalnewlinedecoder_methods[] = {
5697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"decode", (PyCFunction)incrementalnewlinedecoder_decode, METH_VARARGS|METH_KEYWORDS},
5707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"getstate", (PyCFunction)incrementalnewlinedecoder_getstate, METH_NOARGS},
5717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"setstate", (PyCFunction)incrementalnewlinedecoder_setstate, METH_O},
5727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"reset", (PyCFunction)incrementalnewlinedecoder_reset, METH_NOARGS},
5737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL}
5747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
5757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyGetSetDef incrementalnewlinedecoder_getset[] = {
5777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"newlines", (getter)incrementalnewlinedecoder_newlines_get, NULL, NULL},
5787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL}
5797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
5807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
5817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyTypeObject PyIncrementalNewlineDecoder_Type = {
5827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyVarObject_HEAD_INIT(NULL, 0)
5837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "_io.IncrementalNewlineDecoder", /*tp_name*/
5847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    sizeof(nldecoder_object), /*tp_basicsize*/
5857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_itemsize*/
5867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (destructor)incrementalnewlinedecoder_dealloc, /*tp_dealloc*/
5877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_print*/
5887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_getattr*/
5897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_setattr*/
5907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_compare */
5917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_repr*/
5927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_number*/
5937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_sequence*/
5947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_mapping*/
5957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_hash */
5967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_call*/
5977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_str*/
5987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_getattro*/
5997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_setattro*/
6007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_buffer*/
6017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
6027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    incrementalnewlinedecoder_doc,          /* tp_doc */
6037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_traverse */
6047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_clear */
6057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_richcompare */
6067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_weaklistoffset*/
6077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_iter */
6087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_iternext */
6097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    incrementalnewlinedecoder_methods, /* tp_methods */
6107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_members */
6117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    incrementalnewlinedecoder_getset, /* tp_getset */
6127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_base */
6137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_dict */
6147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_descr_get */
6157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_descr_set */
6167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_dictoffset */
6177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (initproc)incrementalnewlinedecoder_init, /* tp_init */
6187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_alloc */
6197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyType_GenericNew,          /* tp_new */
6207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
6217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
6227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
6237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* TextIOWrapper */
6247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
6257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyDoc_STRVAR(textiowrapper_doc,
6267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "Character and line based layer over a BufferedIOBase object, buffer.\n"
6277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
6287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "encoding gives the name of the encoding that the stream will be\n"
6297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "decoded or encoded with. It defaults to locale.getpreferredencoding.\n"
6307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
6317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "errors determines the strictness of encoding and decoding (see the\n"
6327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "codecs.register) and defaults to \"strict\".\n"
6337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
6347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "newline controls how line endings are handled. It can be None, '',\n"
6357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "'\\n', '\\r', and '\\r\\n'.  It works as follows:\n"
6367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
6377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "* On input, if newline is None, universal newlines mode is\n"
6387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "  enabled. Lines in the input can end in '\\n', '\\r', or '\\r\\n', and\n"
6397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "  these are translated into '\\n' before being returned to the\n"
6407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "  caller. If it is '', universal newline mode is enabled, but line\n"
6417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "  endings are returned to the caller untranslated. If it has any of\n"
6427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "  the other legal values, input lines are only terminated by the given\n"
6437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "  string, and the line ending is returned to the caller untranslated.\n"
6447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
6457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "* On output, if newline is None, any '\\n' characters written are\n"
6467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "  translated to the system default line separator, os.linesep. If\n"
6477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "  newline is '', no translation takes place. If newline is any of the\n"
6487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "  other legal values, any '\\n' characters written are translated to\n"
6497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "  the given string.\n"
6507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "\n"
6517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "If line_buffering is True, a call to flush is implied when a call to\n"
6527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "write contains a newline character."
6537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    );
6547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
6557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltypedef PyObject *
6567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        (*encodefunc_t)(PyObject *, PyObject *);
6577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
6587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltypedef struct
6597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
6607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject_HEAD
6617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int ok; /* initialized? */
6627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int detached;
6637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t chunk_size;
6647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *buffer;
6657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *encoding;
6667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *encoder;
6677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *decoder;
6687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *readnl;
6697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *errors;
6707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    const char *writenl; /* utf-8 encoded, NULL stands for \n */
6717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char line_buffering;
6727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char readuniversal;
6737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char readtranslate;
6747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char writetranslate;
6757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char seekable;
6767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char telling;
6777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Specialized encoding func (see below) */
6787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    encodefunc_t encodefunc;
6797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Whether or not it's the start of the stream */
6807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char encoding_start_of_stream;
6817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
6827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Reads and writes are internally buffered in order to speed things up.
6837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       However, any read will first flush the write buffer if itsn't empty.
6847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
6857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       Please also note that text to be written is first encoded before being
6867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       buffered. This is necessary so that encoding errors are immediately
6877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       reported to the caller, but it unfortunately means that the
6887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       IncrementalEncoder (whose encode() method is always written in Python)
6897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       becomes a bottleneck for small writes.
6907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    */
6917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *decoded_chars;       /* buffer for text returned from decoder */
6927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t decoded_chars_used; /* offset into _decoded_chars for read() */
6937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *pending_bytes;       /* list of bytes objects waiting to be
6947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                      written, or NULL */
6957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t pending_bytes_count;
6967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *snapshot;
6977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* snapshot is either None, or a tuple (dec_flags, next_input) where
6987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     * dec_flags is the second (integer) item of the decoder state and
6997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     * next_input is the chunk of input bytes that comes next after the
7007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     * snapshot point.  We use this to reconstruct decoder states in tell().
7017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     */
7027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Cache raw object if it's a FileIO object */
7047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *raw;
7057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *weakreflist;
7077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *dict;
7087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel} textio;
7097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* A couple of specialized cases in order to bypass the slow incremental
7127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel   encoding methods for the most popular encodings. */
7137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
7157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielascii_encode(textio *self, PyObject *text)
7167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
7177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyUnicode_EncodeASCII(PyUnicode_AS_UNICODE(text),
7187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 PyUnicode_GET_SIZE(text),
7197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 PyBytes_AS_STRING(self->errors));
7207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
7217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
7237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielutf16be_encode(textio *self, PyObject *text)
7247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
7257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyUnicode_EncodeUTF16(PyUnicode_AS_UNICODE(text),
7267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 PyUnicode_GET_SIZE(text),
7277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 PyBytes_AS_STRING(self->errors), 1);
7287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
7297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
7317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielutf16le_encode(textio *self, PyObject *text)
7327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
7337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyUnicode_EncodeUTF16(PyUnicode_AS_UNICODE(text),
7347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 PyUnicode_GET_SIZE(text),
7357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 PyBytes_AS_STRING(self->errors), -1);
7367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
7377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
7397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielutf16_encode(textio *self, PyObject *text)
7407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
7417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!self->encoding_start_of_stream) {
7427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Skip the BOM and use native byte ordering */
7437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#if defined(WORDS_BIGENDIAN)
7447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return utf16be_encode(self, text);
7457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#else
7467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return utf16le_encode(self, text);
7477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#endif
7487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
7497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyUnicode_EncodeUTF16(PyUnicode_AS_UNICODE(text),
7507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 PyUnicode_GET_SIZE(text),
7517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 PyBytes_AS_STRING(self->errors), 0);
7527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
7537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
7557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielutf32be_encode(textio *self, PyObject *text)
7567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
7577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyUnicode_EncodeUTF32(PyUnicode_AS_UNICODE(text),
7587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 PyUnicode_GET_SIZE(text),
7597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 PyBytes_AS_STRING(self->errors), 1);
7607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
7617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
7637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielutf32le_encode(textio *self, PyObject *text)
7647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
7657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyUnicode_EncodeUTF32(PyUnicode_AS_UNICODE(text),
7667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 PyUnicode_GET_SIZE(text),
7677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 PyBytes_AS_STRING(self->errors), -1);
7687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
7697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
7717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielutf32_encode(textio *self, PyObject *text)
7727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
7737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!self->encoding_start_of_stream) {
7747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Skip the BOM and use native byte ordering */
7757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#if defined(WORDS_BIGENDIAN)
7767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return utf32be_encode(self, text);
7777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#else
7787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return utf32le_encode(self, text);
7797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#endif
7807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
7817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyUnicode_EncodeUTF32(PyUnicode_AS_UNICODE(text),
7827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 PyUnicode_GET_SIZE(text),
7837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                 PyBytes_AS_STRING(self->errors), 0);
7847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
7857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
7877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielutf8_encode(textio *self, PyObject *text)
7887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
7897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyUnicode_EncodeUTF8(PyUnicode_AS_UNICODE(text),
7907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                PyUnicode_GET_SIZE(text),
7917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                PyBytes_AS_STRING(self->errors));
7927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
7937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
7947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
7957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniellatin1_encode(textio *self, PyObject *text)
7967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
7977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyUnicode_EncodeLatin1(PyUnicode_AS_UNICODE(text),
7987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                  PyUnicode_GET_SIZE(text),
7997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                  PyBytes_AS_STRING(self->errors));
8007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
8017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* Map normalized encoding names onto the specialized encoding funcs */
8037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltypedef struct {
8057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    const char *name;
8067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    encodefunc_t encodefunc;
8077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel} encodefuncentry;
8087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic encodefuncentry encodefuncs[] = {
8107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"ascii",       (encodefunc_t) ascii_encode},
8117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"iso8859-1",   (encodefunc_t) latin1_encode},
8127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"utf-8",       (encodefunc_t) utf8_encode},
8137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"utf-16-be",   (encodefunc_t) utf16be_encode},
8147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"utf-16-le",   (encodefunc_t) utf16le_encode},
8157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"utf-16",      (encodefunc_t) utf16_encode},
8167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"utf-32-be",   (encodefunc_t) utf32be_encode},
8177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"utf-32-le",   (encodefunc_t) utf32le_encode},
8187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"utf-32",      (encodefunc_t) utf32_encode},
8197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL, NULL}
8207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
8217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
8247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_init(textio *self, PyObject *args, PyObject *kwds)
8257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
8267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char *kwlist[] = {"buffer", "encoding", "errors",
8277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                      "newline", "line_buffering",
8287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                      NULL};
8297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *buffer, *raw;
8307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char *encoding = NULL;
8317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char *errors = NULL;
8327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char *newline = NULL;
8337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int line_buffering = 0;
8347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res;
8367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int r;
8377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->ok = 0;
8397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->detached = 0;
8407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|zzzi:fileio",
8417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                     kwlist, &buffer, &encoding, &errors,
8427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                     &newline, &line_buffering))
8437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
8447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (newline && newline[0] != '\0'
8467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        && !(newline[0] == '\n' && newline[1] == '\0')
8477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        && !(newline[0] == '\r' && newline[1] == '\0')
8487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        && !(newline[0] == '\r' && newline[1] == '\n' && newline[2] == '\0')) {
8497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_Format(PyExc_ValueError,
8507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                     "illegal newline value: %s", newline);
8517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
8527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
8537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->buffer);
8557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->encoding);
8567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->encoder);
8577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->decoder);
8587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->readnl);
8597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->decoded_chars);
8607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->pending_bytes);
8617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->snapshot);
8627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->errors);
8637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->raw);
8647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->decoded_chars_used = 0;
8657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->pending_bytes_count = 0;
8667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->encodefunc = NULL;
8677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->writenl = NULL;
8687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
8697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (encoding == NULL && self->encoding == NULL) {
8707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (_PyIO_locale_module == NULL) {
8717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            _PyIO_locale_module = PyImport_ImportModule("locale");
8727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (_PyIO_locale_module == NULL)
8737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto catch_ImportError;
8747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            else
8757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto use_locale;
8767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
8777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        else {
8787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel          use_locale:
8797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->encoding = PyObject_CallMethod(
8807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                _PyIO_locale_module, "getpreferredencoding", NULL);
8817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (self->encoding == NULL) {
8827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel              catch_ImportError:
8837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                /*
8847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                 Importing locale can raise a ImportError because of
8857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                 _functools, and locale.getpreferredencoding can raise a
8867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                 ImportError if _locale is not available.  These will happen
8877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                 during module building.
8887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                */
8897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (PyErr_ExceptionMatches(PyExc_ImportError)) {
8907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    PyErr_Clear();
8917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    self->encoding = PyString_FromString("ascii");
8927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                }
8937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                else
8947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    goto error;
8957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
8967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            else if (!PyString_Check(self->encoding))
8977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                Py_CLEAR(self->encoding);
8987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
8997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
9007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->encoding != NULL)
9017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        encoding = PyString_AsString(self->encoding);
9027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else if (encoding != NULL) {
9037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->encoding = PyString_FromString(encoding);
9047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (self->encoding == NULL)
9057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
9067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
9077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else {
9087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_IOError,
9097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        "could not determine default encoding");
9107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
9117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
9127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (errors == NULL)
9137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        errors = "strict";
9147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->errors = PyBytes_FromString(errors);
9157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->errors == NULL)
9167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto error;
9177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
9187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->chunk_size = 8192;
9197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->readuniversal = (newline == NULL || newline[0] == '\0');
9207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->line_buffering = line_buffering;
9217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->readtranslate = (newline == NULL);
9227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (newline) {
9237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->readnl = PyString_FromString(newline);
9247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (self->readnl == NULL)
9257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return -1;
9267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
9277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->writetranslate = (newline == NULL || newline[0] != '\0');
9287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!self->readuniversal && self->writetranslate) {
9297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->writenl = PyString_AsString(self->readnl);
9307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (!strcmp(self->writenl, "\n"))
9317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->writenl = NULL;
9327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
9337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#ifdef MS_WINDOWS
9347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else
9357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->writenl = "\r\n";
9367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#endif
9377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
9387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Build the decoder object */
9397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyObject_CallMethod(buffer, "readable", NULL);
9407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
9417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto error;
9427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    r = PyObject_IsTrue(res);
9437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
9447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (r == -1)
9457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto error;
9467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (r == 1) {
9477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->decoder = PyCodec_IncrementalDecoder(
9487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            encoding, errors);
9497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (self->decoder == NULL)
9507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
9517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
9527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (self->readuniversal) {
9537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyObject *incrementalDecoder = PyObject_CallFunction(
9547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                (PyObject *)&PyIncrementalNewlineDecoder_Type,
9557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                "Oi", self->decoder, (int)self->readtranslate);
9567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (incrementalDecoder == NULL)
9577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto error;
9587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_CLEAR(self->decoder);
9597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->decoder = incrementalDecoder;
9607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
9617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
9627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
9637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Build the encoder object */
9647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyObject_CallMethod(buffer, "writable", NULL);
9657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
9667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto error;
9677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    r = PyObject_IsTrue(res);
9687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
9697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (r == -1)
9707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto error;
9717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (r == 1) {
9727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *ci;
9737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->encoder = PyCodec_IncrementalEncoder(
9747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            encoding, errors);
9757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (self->encoder == NULL)
9767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
9777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Get the normalized named of the codec */
9787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        ci = _PyCodec_Lookup(encoding);
9797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (ci == NULL)
9807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
9817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyObject_GetAttrString(ci, "name");
9827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(ci);
9837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (res == NULL) {
9847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (PyErr_ExceptionMatches(PyExc_AttributeError))
9857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                PyErr_Clear();
9867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            else
9877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto error;
9887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
9897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        else if (PyString_Check(res)) {
9907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            encodefuncentry *e = encodefuncs;
9917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            while (e->name != NULL) {
9927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (!strcmp(PyString_AS_STRING(res), e->name)) {
9937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    self->encodefunc = e->encodefunc;
9947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    break;
9957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                }
9967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                e++;
9977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
9987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
9997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_XDECREF(res);
10007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
10017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->buffer = buffer;
10037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_INCREF(buffer);
10047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (Py_TYPE(buffer) == &PyBufferedReader_Type ||
10067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_TYPE(buffer) == &PyBufferedWriter_Type ||
10077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_TYPE(buffer) == &PyBufferedRandom_Type) {
10087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        raw = PyObject_GetAttrString(buffer, "raw");
10097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Cache the raw FileIO object to speed up 'closed' checks */
10107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (raw == NULL) {
10117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (PyErr_ExceptionMatches(PyExc_AttributeError))
10127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                PyErr_Clear();
10137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            else
10147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto error;
10157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
10167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        else if (Py_TYPE(raw) == &PyFileIO_Type)
10177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->raw = raw;
10187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        else
10197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(raw);
10207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
10217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyObject_CallMethod(buffer, "seekable", NULL);
10237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
10247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto error;
10257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    r = PyObject_IsTrue(res);
10267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
10277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (r < 0)
10287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto error;
10297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->seekable = self->telling = r;
10307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->encoding_start_of_stream = 0;
10327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->seekable && self->encoder) {
10337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *cookieObj;
10347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        int cmp;
10357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->encoding_start_of_stream = 1;
10377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        cookieObj = PyObject_CallMethodObjArgs(buffer, _PyIO_str_tell, NULL);
10397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (cookieObj == NULL)
10407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
10417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        cmp = PyObject_RichCompareBool(cookieObj, _PyIO_zero, Py_EQ);
10437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(cookieObj);
10447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (cmp < 0) {
10457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
10467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
10477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (cmp == 0) {
10497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->encoding_start_of_stream = 0;
10507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            res = PyObject_CallMethodObjArgs(self->encoder, _PyIO_str_setstate,
10517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                             _PyIO_zero, NULL);
10527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (res == NULL)
10537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto error;
10547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(res);
10557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
10567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
10577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->ok = 1;
10597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
10607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel  error:
10627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return -1;
10637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
10647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
10667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_textiowrapper_clear(textio *self)
10677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
10687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->ok && _PyIOBase_finalize((PyObject *) self) < 0)
10697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
10707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->ok = 0;
10717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->buffer);
10727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->encoding);
10737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->encoder);
10747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->decoder);
10757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->readnl);
10767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->decoded_chars);
10777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->pending_bytes);
10787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->snapshot);
10797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->errors);
10807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->raw);
10817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
10827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
10837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic void
10857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_dealloc(textio *self)
10867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
10877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_textiowrapper_clear(self) < 0)
10887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return;
10897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    _PyObject_GC_UNTRACK(self);
10907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->weakreflist != NULL)
10917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject_ClearWeakRefs((PyObject *)self);
10927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->dict);
10937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_TYPE(self)->tp_free((PyObject *)self);
10947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
10957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
10967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
10977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_traverse(textio *self, visitproc visit, void *arg)
10987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
10997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_VISIT(self->buffer);
11007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_VISIT(self->encoding);
11017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_VISIT(self->encoder);
11027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_VISIT(self->decoder);
11037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_VISIT(self->readnl);
11047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_VISIT(self->decoded_chars);
11057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_VISIT(self->pending_bytes);
11067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_VISIT(self->snapshot);
11077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_VISIT(self->errors);
11087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_VISIT(self->raw);
11097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_VISIT(self->dict);
11117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
11127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
11137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
11157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_clear(textio *self)
11167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
11177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_textiowrapper_clear(self) < 0)
11187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
11197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->dict);
11207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
11217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
11227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
11247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_closed_get(textio *self, void *context);
11257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* This macro takes some shortcuts to make the common case faster. */
11277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define CHECK_CLOSED(self) \
11287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    do { \
11297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        int r; \
11307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *_res; \
11317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (Py_TYPE(self) == &PyTextIOWrapper_Type) { \
11327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (self->raw != NULL) \
11337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                r = _PyFileIO_closed(self->raw); \
11347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            else { \
11357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                _res = textiowrapper_closed_get(self, NULL); \
11367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (_res == NULL) \
11377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    return NULL; \
11387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                r = PyObject_IsTrue(_res); \
11397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                Py_DECREF(_res); \
11407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (r < 0) \
11417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    return NULL; \
11427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            } \
11437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (r > 0) { \
11447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                PyErr_SetString(PyExc_ValueError, \
11457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                "I/O operation on closed file."); \
11467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                return NULL; \
11477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            } \
11487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        } \
11497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        else if (_PyIOBase_check_closed((PyObject *)self, Py_True) == NULL) \
11507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL; \
11517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    } while (0)
11527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define CHECK_INITIALIZED(self) \
11547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->ok <= 0) { \
11557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_ValueError, \
11567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            "I/O operation on uninitialized object"); \
11577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL; \
11587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
11597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define CHECK_ATTACHED(self) \
11617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self); \
11627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->detached) { \
11637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_ValueError, \
11647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel             "underlying buffer has been detached"); \
11657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL; \
11667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
11677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define CHECK_ATTACHED_INT(self) \
11697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->ok <= 0) { \
11707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_ValueError, \
11717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            "I/O operation on uninitialized object"); \
11727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1; \
11737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    } else if (self->detached) { \
11747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_ValueError, \
11757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel             "underlying buffer has been detached"); \
11767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1; \
11777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
11787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
11817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_detach(textio *self)
11827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
11837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *buffer, *res;
11847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
11857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL);
11867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
11877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
11887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
11897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    buffer = self->buffer;
11907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->buffer = NULL;
11917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->detached = 1;
11927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return buffer;
11937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
11947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
11957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPy_LOCAL_INLINE(const Py_UNICODE *)
11967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielfindchar(const Py_UNICODE *s, Py_ssize_t size, Py_UNICODE ch)
11977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
11987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* like wcschr, but doesn't stop at NULL characters */
11997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    while (size-- > 0) {
12007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (*s == ch)
12017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return s;
12027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        s++;
12037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
12047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return NULL;
12057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
12067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* Flush the internal write buffer. This doesn't explicitly flush the
12087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel   underlying buffered object, though. */
12097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
12107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_textiowrapper_writeflush(textio *self)
12117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
12127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *pending, *b, *ret;
12137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->pending_bytes == NULL)
12157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return 0;
12167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    pending = self->pending_bytes;
12187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_INCREF(pending);
12197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->pending_bytes_count = 0;
12207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->pending_bytes);
12217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    b = _PyBytes_Join(_PyIO_empty_bytes, pending);
12237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(pending);
12247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (b == NULL)
12257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
12267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    ret = NULL;
12277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    do {
12287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        ret = PyObject_CallMethodObjArgs(self->buffer,
12297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                         _PyIO_str_write, b, NULL);
12307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    } while (ret == NULL && _PyIO_trap_eintr());
12317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(b);
12327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (ret == NULL)
12337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
12347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(ret);
12357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
12367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
12377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
12397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_write(textio *self, PyObject *args)
12407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
12417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *ret;
12427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *text; /* owned reference */
12437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *b;
12447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t textlen;
12457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int haslf = 0;
12467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int needflush = 0;
12477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
12497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTuple(args, "U:write", &text)) {
12517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
12527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
12537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_CLOSED(self);
12557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->encoder == NULL) {
12577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_IOError, "not writable");
12587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
12597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
12607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_INCREF(text);
12627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    textlen = PyUnicode_GetSize(text);
12647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if ((self->writetranslate && self->writenl != NULL) || self->line_buffering)
12667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (findchar(PyUnicode_AS_UNICODE(text),
12677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                     PyUnicode_GET_SIZE(text), '\n'))
12687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            haslf = 1;
12697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (haslf && self->writetranslate && self->writenl != NULL) {
12717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *newtext = PyObject_CallMethod(
12727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            text, "replace", "ss", "\n", self->writenl);
12737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(text);
12747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (newtext == NULL)
12757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
12767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        text = newtext;
12777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
12787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->line_buffering &&
12807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        (haslf ||
12817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel         findchar(PyUnicode_AS_UNICODE(text),
12827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                  PyUnicode_GET_SIZE(text), '\r')))
12837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        needflush = 1;
12847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* XXX What if we were just reading? */
12867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->encodefunc != NULL) {
12877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        b = (*self->encodefunc)((PyObject *) self, text);
12887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->encoding_start_of_stream = 0;
12897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
12907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else
12917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        b = PyObject_CallMethodObjArgs(self->encoder,
12927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                       _PyIO_str_encode, text, NULL);
12937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(text);
12947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (b == NULL)
12957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
12967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
12977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->pending_bytes == NULL) {
12987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->pending_bytes = PyList_New(0);
12997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (self->pending_bytes == NULL) {
13007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(b);
13017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
13027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
13037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->pending_bytes_count = 0;
13047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
13057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (PyList_Append(self->pending_bytes, b) < 0) {
13067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(b);
13077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
13087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
13097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->pending_bytes_count += PyBytes_GET_SIZE(b);
13107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(b);
13117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->pending_bytes_count > self->chunk_size || needflush) {
13127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (_textiowrapper_writeflush(self) < 0)
13137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
13147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
13157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (needflush) {
13177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        ret = PyObject_CallMethodObjArgs(self->buffer, _PyIO_str_flush, NULL);
13187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (ret == NULL)
13197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
13207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(ret);
13217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
13227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->snapshot);
13247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->decoder) {
13267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        ret = PyObject_CallMethod(self->decoder, "reset", NULL);
13277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (ret == NULL)
13287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
13297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(ret);
13307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
13317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyLong_FromSsize_t(textlen);
13337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
13347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* Steal a reference to chars and store it in the decoded_char buffer;
13367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel */
13377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic void
13387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_set_decoded_chars(textio *self, PyObject *chars)
13397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
13407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->decoded_chars);
13417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->decoded_chars = chars;
13427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->decoded_chars_used = 0;
13437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
13447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
13467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_get_decoded_chars(textio *self, Py_ssize_t n)
13477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
13487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *chars;
13497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t avail;
13507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->decoded_chars == NULL)
13527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return PyUnicode_FromStringAndSize(NULL, 0);
13537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    avail = (PyUnicode_GET_SIZE(self->decoded_chars)
13557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel             - self->decoded_chars_used);
13567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    assert(avail >= 0);
13587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n < 0 || n > avail)
13607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        n = avail;
13617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->decoded_chars_used > 0 || n < avail) {
13637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        chars = PyUnicode_FromUnicode(
13647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyUnicode_AS_UNICODE(self->decoded_chars)
13657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            + self->decoded_chars_used, n);
13667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (chars == NULL)
13677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
13687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
13697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else {
13707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        chars = self->decoded_chars;
13717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_INCREF(chars);
13727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
13737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->decoded_chars_used += n;
13757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return chars;
13767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
13777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* Read and decode the next chunk of data from the BufferedReader.
13797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel */
13807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
13817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_read_chunk(textio *self)
13827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
13837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *dec_buffer = NULL;
13847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *dec_flags = NULL;
13857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *input_chunk = NULL;
13867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *decoded_chars, *chunk_size;
13877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int eof;
13887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* The return value is True unless EOF was reached.  The decoded string is
13907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     * placed in self._decoded_chars (replacing its previous value).  The
13917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     * entire input chunk is sent to the decoder, though some of it may remain
13927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     * buffered in the decoder, yet to be converted.
13937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     */
13947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
13957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->decoder == NULL) {
13967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_IOError, "not readable");
13977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
13987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
13997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->telling) {
14017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* To prepare for tell(), we need to snapshot a point in the file
14027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel         * where the decoder's input buffer is empty.
14037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel         */
14047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *state = PyObject_CallMethodObjArgs(self->decoder,
14067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                                     _PyIO_str_getstate, NULL);
14077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (state == NULL)
14087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return -1;
14097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Given this, we know there was a valid snapshot point
14107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel         * len(dec_buffer) bytes ago with decoder state (b'', dec_flags).
14117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel         */
14127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (PyArg_Parse(state, "(OO)", &dec_buffer, &dec_flags) < 0) {
14137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(state);
14147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return -1;
14157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
14167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_INCREF(dec_buffer);
14177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_INCREF(dec_flags);
14187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(state);
14197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
14207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Read a chunk, decode it, and put the result in self._decoded_chars. */
14227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    chunk_size = PyLong_FromSsize_t(self->chunk_size);
14237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (chunk_size == NULL)
14247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
14257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    input_chunk = PyObject_CallMethodObjArgs(self->buffer,
14267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        _PyIO_str_read1, chunk_size, NULL);
14277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(chunk_size);
14287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (input_chunk == NULL)
14297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
14307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyBytes_Check(input_chunk)) {
14317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_Format(PyExc_TypeError,
14327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                     "underlying read1() should have returned a bytes object, "
14337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                     "not '%.200s'", Py_TYPE(input_chunk)->tp_name);
14347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
14357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
14367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    eof = (PyBytes_Size(input_chunk) == 0);
14387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (Py_TYPE(self->decoder) == &PyIncrementalNewlineDecoder_Type) {
14407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        decoded_chars = _PyIncrementalNewlineDecoder_decode(
14417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->decoder, input_chunk, eof);
14427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
14437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else {
14447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        decoded_chars = PyObject_CallMethodObjArgs(self->decoder,
14457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            _PyIO_str_decode, input_chunk, eof ? Py_True : Py_False, NULL);
14467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
14477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (check_decoded(decoded_chars) < 0)
14497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
14507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    textiowrapper_set_decoded_chars(self, decoded_chars);
14517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (PyUnicode_GET_SIZE(decoded_chars) > 0)
14527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        eof = 0;
14537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->telling) {
14557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* At the snapshot point, len(dec_buffer) bytes before the read, the
14567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel         * next input to be decoded is dec_buffer + input_chunk.
14577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel         */
14587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *next_input = PyNumber_Add(dec_buffer, input_chunk);
14597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (next_input == NULL)
14607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
14617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (!PyBytes_Check(next_input)) {
14627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_Format(PyExc_TypeError,
14637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         "decoder getstate() should have returned a bytes "
14647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         "object, not '%.200s'",
14657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         Py_TYPE(next_input)->tp_name);
14667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(next_input);
14677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
14687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
14697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(dec_buffer);
14707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_CLEAR(self->snapshot);
14717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->snapshot = Py_BuildValue("NN", dec_flags, next_input);
14727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
14737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(input_chunk);
14747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return (eof == 0);
14767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel  fail:
14787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(dec_buffer);
14797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(dec_flags);
14807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(input_chunk);
14817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return -1;
14827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
14837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
14857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_read(textio *self, PyObject *args)
14867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
14877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t n = -1;
14887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *result = NULL, *chunks = NULL;
14897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
14917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTuple(args, "|O&:read", &_PyIO_ConvertSsize_t, &n))
14937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
14947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_CLOSED(self);
14967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
14977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->decoder == NULL) {
14987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_IOError, "not readable");
14997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
15007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
15017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_textiowrapper_writeflush(self) < 0)
15037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
15047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n < 0) {
15067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Read everything */
15077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *bytes = PyObject_CallMethod(self->buffer, "read", NULL);
15087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *decoded, *final;
15097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (bytes == NULL)
15107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
15117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        decoded = PyObject_CallMethodObjArgs(self->decoder, _PyIO_str_decode,
15127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                             bytes, Py_True, NULL);
15137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(bytes);
15147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (check_decoded(decoded) < 0)
15157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
15167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        result = textiowrapper_get_decoded_chars(self, -1);
15187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (result == NULL) {
15207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(decoded);
15217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
15227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
15237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        final = PyUnicode_Concat(result, decoded);
15257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(result);
15267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(decoded);
15277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (final == NULL)
15287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
15297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_CLEAR(self->snapshot);
15317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return final;
15327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
15337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else {
15347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        int res = 1;
15357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_ssize_t remaining = n;
15367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        result = textiowrapper_get_decoded_chars(self, n);
15387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (result == NULL)
15397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
15407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        remaining -= PyUnicode_GET_SIZE(result);
15417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Keep reading chunks until we have n characters to return */
15437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        while (remaining > 0) {
15447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            res = textiowrapper_read_chunk(self);
15457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (res < 0) {
15467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
15477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                   when EINTR occurs so we needn't do it ourselves. */
15487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (_PyIO_trap_eintr()) {
15497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    continue;
15507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                }
15517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto fail;
15527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
15537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (res == 0)  /* EOF */
15547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                break;
15557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (chunks == NULL) {
15567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                chunks = PyList_New(0);
15577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (chunks == NULL)
15587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    goto fail;
15597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
15607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (PyList_Append(chunks, result) < 0)
15617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto fail;
15627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(result);
15637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            result = textiowrapper_get_decoded_chars(self, remaining);
15647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (result == NULL)
15657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto fail;
15667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            remaining -= PyUnicode_GET_SIZE(result);
15677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
15687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (chunks != NULL) {
15697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (result != NULL && PyList_Append(chunks, result) < 0)
15707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto fail;
15717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_CLEAR(result);
15727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            result = PyUnicode_Join(_PyIO_empty_str, chunks);
15737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (result == NULL)
15747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto fail;
15757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_CLEAR(chunks);
15767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
15777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return result;
15787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
15797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel  fail:
15807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(result);
15817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(chunks);
15827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return NULL;
15837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
15847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
15867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* NOTE: `end` must point to the real end of the Py_UNICODE storage,
15877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel   that is to the NUL character. Otherwise the function will produce
15887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel   incorrect results. */
15897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic Py_UNICODE *
15907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielfind_control_char(Py_UNICODE *start, Py_UNICODE *end, Py_UNICODE ch)
15917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
15927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_UNICODE *s = start;
15937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    for (;;) {
15947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        while (*s > ch)
15957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            s++;
15967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (*s == ch)
15977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return s;
15987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (s == end)
15997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
16007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        s++;
16017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
16027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
16037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPy_ssize_t
16057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_PyIO_find_line_ending(
16067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int translated, int universal, PyObject *readnl,
16077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_UNICODE *start, Py_UNICODE *end, Py_ssize_t *consumed)
16087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
16097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t len = end - start;
16107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (translated) {
16127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Newlines are already translated, only search for \n */
16137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_UNICODE *pos = find_control_char(start, end, '\n');
16147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (pos != NULL)
16157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return pos - start + 1;
16167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        else {
16177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            *consumed = len;
16187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return -1;
16197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
16207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
16217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else if (universal) {
16227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Universal newline search. Find any of \r, \r\n, \n
16237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel         * The decoder ensures that \r\n are not split in two pieces
16247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel         */
16257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_UNICODE *s = start;
16267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        for (;;) {
16277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_UNICODE ch;
16287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            /* Fast path for non-control chars. The loop always ends
16297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel               since the Py_UNICODE storage is NUL-terminated. */
16307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            while (*s > '\r')
16317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                s++;
16327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (s >= end) {
16337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                *consumed = len;
16347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                return -1;
16357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
16367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            ch = *s++;
16377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (ch == '\n')
16387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                return s - start;
16397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (ch == '\r') {
16407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (*s == '\n')
16417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    return s - start + 1;
16427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                else
16437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    return s - start;
16447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
16457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
16467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
16477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else {
16487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Non-universal mode. */
16497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_ssize_t readnl_len = PyString_GET_SIZE(readnl);
16507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        unsigned char *nl = (unsigned char *) PyString_AS_STRING(readnl);
16517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (readnl_len == 1) {
16527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_UNICODE *pos = find_control_char(start, end, nl[0]);
16537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (pos != NULL)
16547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                return pos - start + 1;
16557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            *consumed = len;
16567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return -1;
16577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
16587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        else {
16597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_UNICODE *s = start;
16607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_UNICODE *e = end - readnl_len + 1;
16617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_UNICODE *pos;
16627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (e < s)
16637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                e = s;
16647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            while (s < e) {
16657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                Py_ssize_t i;
16667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                Py_UNICODE *pos = find_control_char(s, end, nl[0]);
16677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (pos == NULL || pos >= e)
16687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    break;
16697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                for (i = 1; i < readnl_len; i++) {
16707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    if (pos[i] != nl[i])
16717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        break;
16727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                }
16737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (i == readnl_len)
16747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    return pos - start + readnl_len;
16757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                s = pos + 1;
16767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
16777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            pos = find_control_char(e, end, nl[0]);
16787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (pos == NULL)
16797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                *consumed = len;
16807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            else
16817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                *consumed = pos - start;
16827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return -1;
16837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
16847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
16857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
16867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
16887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_textiowrapper_readline(textio *self, Py_ssize_t limit)
16897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
16907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *line = NULL, *chunks = NULL, *remaining = NULL;
16917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t start, endpos, chunked, offset_to_buffer;
16927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int res;
16937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_CLOSED(self);
16957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_textiowrapper_writeflush(self) < 0)
16977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
16987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
16997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    chunked = 0;
17007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
17017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    while (1) {
17027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_UNICODE *ptr;
17037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_ssize_t line_len;
17047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_ssize_t consumed = 0;
17057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
17067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* First, get some data if necessary */
17077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = 1;
17087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        while (!self->decoded_chars ||
17097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel               !PyUnicode_GET_SIZE(self->decoded_chars)) {
17107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            res = textiowrapper_read_chunk(self);
17117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (res < 0) {
17127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
17137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                   when EINTR occurs so we needn't do it ourselves. */
17147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (_PyIO_trap_eintr()) {
17157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    continue;
17167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                }
17177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto error;
17187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
17197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (res == 0)
17207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                break;
17217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
17227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (res == 0) {
17237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            /* end of file */
17247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            textiowrapper_set_decoded_chars(self, NULL);
17257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_CLEAR(self->snapshot);
17267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            start = endpos = offset_to_buffer = 0;
17277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            break;
17287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
17297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
17307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (remaining == NULL) {
17317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            line = self->decoded_chars;
17327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            start = self->decoded_chars_used;
17337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            offset_to_buffer = 0;
17347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_INCREF(line);
17357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
17367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        else {
17377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            assert(self->decoded_chars_used == 0);
17387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            line = PyUnicode_Concat(remaining, self->decoded_chars);
17397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            start = 0;
17407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            offset_to_buffer = PyUnicode_GET_SIZE(remaining);
17417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_CLEAR(remaining);
17427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (line == NULL)
17437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto error;
17447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
17457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
17467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        ptr = PyUnicode_AS_UNICODE(line);
17477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        line_len = PyUnicode_GET_SIZE(line);
17487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
17497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        endpos = _PyIO_find_line_ending(
17507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->readtranslate, self->readuniversal, self->readnl,
17517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            ptr + start, ptr + line_len, &consumed);
17527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (endpos >= 0) {
17537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            endpos += start;
17547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (limit >= 0 && (endpos - start) + chunked >= limit)
17557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                endpos = start + limit - chunked;
17567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            break;
17577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
17587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
17597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* We can put aside up to `endpos` */
17607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        endpos = consumed + start;
17617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (limit >= 0 && (endpos - start) + chunked >= limit) {
17627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            /* Didn't find line ending, but reached length limit */
17637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            endpos = start + limit - chunked;
17647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            break;
17657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
17667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
17677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (endpos > start) {
17687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            /* No line ending seen yet - put aside current data */
17697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyObject *s;
17707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (chunks == NULL) {
17717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                chunks = PyList_New(0);
17727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (chunks == NULL)
17737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    goto error;
17747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
17757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            s = PyUnicode_FromUnicode(ptr + start, endpos - start);
17767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (s == NULL)
17777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto error;
17787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (PyList_Append(chunks, s) < 0) {
17797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                Py_DECREF(s);
17807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto error;
17817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
17827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            chunked += PyUnicode_GET_SIZE(s);
17837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(s);
17847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
17857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* There may be some remaining bytes we'll have to prepend to the
17867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel           next chunk of data */
17877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (endpos < line_len) {
17887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            remaining = PyUnicode_FromUnicode(
17897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    ptr + endpos, line_len - endpos);
17907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (remaining == NULL)
17917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto error;
17927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
17937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_CLEAR(line);
17947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* We have consumed the buffer */
17957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        textiowrapper_set_decoded_chars(self, NULL);
17967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
17977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
17987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (line != NULL) {
17997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Our line ends in the current buffer */
18007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->decoded_chars_used = endpos - offset_to_buffer;
18017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (start > 0 || endpos < PyUnicode_GET_SIZE(line)) {
18027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (start == 0 && Py_REFCNT(line) == 1) {
18037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (PyUnicode_Resize(&line, endpos) < 0)
18047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    goto error;
18057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
18067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            else {
18077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                PyObject *s = PyUnicode_FromUnicode(
18087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        PyUnicode_AS_UNICODE(line) + start, endpos - start);
18097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                Py_CLEAR(line);
18107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                if (s == NULL)
18117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    goto error;
18127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                line = s;
18137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            }
18147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
18157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
18167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (remaining != NULL) {
18177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (chunks == NULL) {
18187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            chunks = PyList_New(0);
18197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (chunks == NULL)
18207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto error;
18217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
18227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (PyList_Append(chunks, remaining) < 0)
18237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
18247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_CLEAR(remaining);
18257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
18267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (chunks != NULL) {
18277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (line != NULL && PyList_Append(chunks, line) < 0)
18287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
18297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_CLEAR(line);
18307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        line = PyUnicode_Join(_PyIO_empty_str, chunks);
18317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (line == NULL)
18327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
18337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(chunks);
18347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
18357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (line == NULL)
18367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        line = PyUnicode_FromStringAndSize(NULL, 0);
18377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return line;
18397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel  error:
18417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(chunks);
18427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(remaining);
18437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(line);
18447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return NULL;
18457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
18467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
18487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_readline(textio *self, PyObject *args)
18497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
18507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *limitobj = NULL;
18517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t limit = -1;
18527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
18547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTuple(args, "|O:readline", &limitobj)) {
18557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
18567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
18577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (limitobj) {
18587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (!PyNumber_Check(limitobj)) {
18597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_Format(PyExc_TypeError,
18607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         "integer argument expected, got '%.200s'",
18617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         Py_TYPE(limitobj)->tp_name);
18627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
18637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
18647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        limit = PyNumber_AsSsize_t(limitobj, PyExc_OverflowError);
18657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (limit == -1 && PyErr_Occurred())
18667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
18677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
18687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return _textiowrapper_readline(self, limit);
18697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
18707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* Seek and Tell */
18727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltypedef struct {
18747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_off_t start_pos;
18757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int dec_flags;
18767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int bytes_to_feed;
18777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int chars_to_skip;
18787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char need_eof;
18797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel} cookie_type;
18807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/*
18827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel   To speed up cookie packing/unpacking, we store the fields in a temporary
18837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel   string and call _PyLong_FromByteArray() or _PyLong_AsByteArray (resp.).
18847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel   The following macros define at which offsets in the intermediary byte
18857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel   string the various CookieStruct fields will be stored.
18867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel */
18877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#define COOKIE_BUF_LEN      (sizeof(Py_off_t) + 3 * sizeof(int) + sizeof(char))
18897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#if defined(WORDS_BIGENDIAN)
18917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel# define IS_LITTLE_ENDIAN   0
18937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* We want the least significant byte of start_pos to also be the least
18957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel   significant byte of the cookie, which means that in big-endian mode we
18967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel   must copy the fields in reverse order. */
18977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
18987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel# define OFF_START_POS      (sizeof(char) + 3 * sizeof(int))
18997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel# define OFF_DEC_FLAGS      (sizeof(char) + 2 * sizeof(int))
19007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel# define OFF_BYTES_TO_FEED  (sizeof(char) + sizeof(int))
19017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel# define OFF_CHARS_TO_SKIP  (sizeof(char))
19027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel# define OFF_NEED_EOF       0
19037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#else
19057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel# define IS_LITTLE_ENDIAN   1
19077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* Little-endian mode: the least significant byte of start_pos will
19097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel   naturally end up the least significant byte of the cookie. */
19107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel# define OFF_START_POS      0
19127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel# define OFF_DEC_FLAGS      (sizeof(Py_off_t))
19137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel# define OFF_BYTES_TO_FEED  (sizeof(Py_off_t) + sizeof(int))
19147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel# define OFF_CHARS_TO_SKIP  (sizeof(Py_off_t) + 2 * sizeof(int))
19157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel# define OFF_NEED_EOF       (sizeof(Py_off_t) + 3 * sizeof(int))
19167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#endif
19187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
19207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_parse_cookie(cookie_type *cookie, PyObject *cookieObj)
19217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
19227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    unsigned char buffer[COOKIE_BUF_LEN];
19237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyLongObject *cookieLong = (PyLongObject *)PyNumber_Long(cookieObj);
19247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (cookieLong == NULL)
19257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
19267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_PyLong_AsByteArray(cookieLong, buffer, sizeof(buffer),
19287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                            IS_LITTLE_ENDIAN, 0) < 0) {
19297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(cookieLong);
19307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
19317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
19327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(cookieLong);
19337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    memcpy(&cookie->start_pos, buffer + OFF_START_POS, sizeof(cookie->start_pos));
19357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    memcpy(&cookie->dec_flags, buffer + OFF_DEC_FLAGS, sizeof(cookie->dec_flags));
19367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    memcpy(&cookie->bytes_to_feed, buffer + OFF_BYTES_TO_FEED, sizeof(cookie->bytes_to_feed));
19377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    memcpy(&cookie->chars_to_skip, buffer + OFF_CHARS_TO_SKIP, sizeof(cookie->chars_to_skip));
19387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    memcpy(&cookie->need_eof, buffer + OFF_NEED_EOF, sizeof(cookie->need_eof));
19397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
19417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
19427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
19447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_build_cookie(cookie_type *cookie)
19457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
19467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    unsigned char buffer[COOKIE_BUF_LEN];
19477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    memcpy(buffer + OFF_START_POS, &cookie->start_pos, sizeof(cookie->start_pos));
19497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    memcpy(buffer + OFF_DEC_FLAGS, &cookie->dec_flags, sizeof(cookie->dec_flags));
19507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    memcpy(buffer + OFF_BYTES_TO_FEED, &cookie->bytes_to_feed, sizeof(cookie->bytes_to_feed));
19517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    memcpy(buffer + OFF_CHARS_TO_SKIP, &cookie->chars_to_skip, sizeof(cookie->chars_to_skip));
19527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    memcpy(buffer + OFF_NEED_EOF, &cookie->need_eof, sizeof(cookie->need_eof));
19537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return _PyLong_FromByteArray(buffer, sizeof(buffer), IS_LITTLE_ENDIAN, 0);
19557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
19567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#undef IS_LITTLE_ENDIAN
19577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
19597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_textiowrapper_decoder_setstate(textio *self, cookie_type *cookie)
19607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
19617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res;
19627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* When seeking to the start of the stream, we call decoder.reset()
19637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       rather than decoder.getstate().
19647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       This is for a few decoders such as utf-16 for which the state value
19657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       at start is not (b"", 0) but e.g. (b"", 2) (meaning, in the case of
19667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel       utf-16, that we are expecting a BOM).
19677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    */
19687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (cookie->start_pos == 0 && cookie->dec_flags == 0)
19697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyObject_CallMethodObjArgs(self->decoder, _PyIO_str_reset, NULL);
19707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else
19717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyObject_CallMethod(self->decoder, "setstate",
19727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                  "((si))", "", cookie->dec_flags);
19737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
19747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
19757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
19767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
19777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
19787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
19807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel_textiowrapper_encoder_setstate(textio *self, cookie_type *cookie)
19817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
19827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res;
19837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Same as _textiowrapper_decoder_setstate() above. */
19847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (cookie->start_pos == 0 && cookie->dec_flags == 0) {
19857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyObject_CallMethodObjArgs(self->encoder, _PyIO_str_reset, NULL);
19867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->encoding_start_of_stream = 1;
19877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
19887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else {
19897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyObject_CallMethodObjArgs(self->encoder, _PyIO_str_setstate,
19907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                         _PyIO_zero, NULL);
19917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->encoding_start_of_stream = 0;
19927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
19937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
19947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
19957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
19967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
19977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
19987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
19997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
20007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_seek(textio *self, PyObject *args)
20017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
20027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *cookieObj, *posobj;
20037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    cookie_type cookie;
20047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int whence = 0;
20057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res;
20067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int cmp;
20077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
20097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTuple(args, "O|i:seek", &cookieObj, &whence))
20117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
20127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_CLOSED(self);
20137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_INCREF(cookieObj);
20157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!self->seekable) {
20177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_IOError,
20187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        "underlying stream is not seekable");
20197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
20207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
20217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (whence == 1) {
20237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* seek relative to current position */
20247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        cmp = PyObject_RichCompareBool(cookieObj, _PyIO_zero, Py_EQ);
20257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (cmp < 0)
20267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
20277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (cmp == 0) {
20297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_SetString(PyExc_IOError,
20307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                            "can't do nonzero cur-relative seeks");
20317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
20327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
20337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Seeking to the current position should attempt to
20357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel         * sync the underlying buffer with the current position.
20367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel         */
20377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(cookieObj);
20387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        cookieObj = PyObject_CallMethod((PyObject *)self, "tell", NULL);
20397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (cookieObj == NULL)
20407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
20417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
20427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else if (whence == 2) {
20437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* seek relative to end of file */
20447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        cmp = PyObject_RichCompareBool(cookieObj, _PyIO_zero, Py_EQ);
20467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (cmp < 0)
20477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
20487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (cmp == 0) {
20507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_SetString(PyExc_IOError,
20517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                            "can't do nonzero end-relative seeks");
20527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
20537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
20547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyObject_CallMethod((PyObject *)self, "flush", NULL);
20567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (res == NULL)
20577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
20587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(res);
20597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        textiowrapper_set_decoded_chars(self, NULL);
20617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_CLEAR(self->snapshot);
20627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (self->decoder) {
20637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            res = PyObject_CallMethod(self->decoder, "reset", NULL);
20647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            if (res == NULL)
20657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                goto fail;
20667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(res);
20677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
20687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyObject_CallMethod(self->buffer, "seek", "ii", 0, 2);
20707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_XDECREF(cookieObj);
20717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return res;
20727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
20737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else if (whence != 0) {
20747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_Format(PyExc_ValueError,
20757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                     "invalid whence (%d, should be 0, 1 or 2)", whence);
20767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
20777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
20787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    cmp = PyObject_RichCompareBool(cookieObj, _PyIO_zero, Py_LT);
20807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (cmp < 0)
20817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
20827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (cmp == 1) {
20847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *repr = PyObject_Repr(cookieObj);
20857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (repr != NULL) {
20867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_Format(PyExc_ValueError,
20877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         "negative seek position %s",
20887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         PyString_AS_STRING(repr));
20897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(repr);
20907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
20917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
20927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
20937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL);
20957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
20967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
20977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
20987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
20997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* The strategy of seek() is to go back to the safe start point
21007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     * and replay the effect of read(chars_to_skip) from there.
21017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     */
21027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (textiowrapper_parse_cookie(&cookie, cookieObj) < 0)
21037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
21047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Seek back to the safe start point. */
21067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    posobj = PyLong_FromOff_t(cookie.start_pos);
21077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (posobj == NULL)
21087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
21097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyObject_CallMethodObjArgs(self->buffer,
21107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                     _PyIO_str_seek, posobj, NULL);
21117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(posobj);
21127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
21137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
21147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
21157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    textiowrapper_set_decoded_chars(self, NULL);
21177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_CLEAR(self->snapshot);
21187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Restore the decoder to its state from the safe start point. */
21207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->decoder) {
21217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (_textiowrapper_decoder_setstate(self, &cookie) < 0)
21227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
21237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
21247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (cookie.chars_to_skip) {
21267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Just like _read_chunk, feed the decoder and save a snapshot. */
21277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *input_chunk = PyObject_CallMethod(
21287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->buffer, "read", "i", cookie.bytes_to_feed);
21297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *decoded;
21307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (input_chunk == NULL)
21327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
21337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (!PyBytes_Check(input_chunk)) {
21357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_Format(PyExc_TypeError,
21367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         "underlying read() should have returned a bytes "
21377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         "object, not '%.200s'",
21387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         Py_TYPE(input_chunk)->tp_name);
21397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(input_chunk);
21407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
21417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
21427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->snapshot = Py_BuildValue("iN", cookie.dec_flags, input_chunk);
21447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (self->snapshot == NULL) {
21457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(input_chunk);
21467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
21477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
21487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        decoded = PyObject_CallMethod(self->decoder, "decode",
21507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                      "Oi", input_chunk, (int)cookie.need_eof);
21517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (check_decoded(decoded) < 0)
21537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
21547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        textiowrapper_set_decoded_chars(self, decoded);
21567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Skip chars_to_skip of the decoded characters. */
21587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (PyUnicode_GetSize(self->decoded_chars) < cookie.chars_to_skip) {
21597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_SetString(PyExc_IOError, "can't restore logical file position");
21607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
21617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
21627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->decoded_chars_used = cookie.chars_to_skip;
21637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
21647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else {
21657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->snapshot = Py_BuildValue("is", cookie.dec_flags, "");
21667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (self->snapshot == NULL)
21677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
21687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
21697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Finally, reset the encoder (merely useful for proper BOM handling) */
21717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->encoder) {
21727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (_textiowrapper_encoder_setstate(self, &cookie) < 0)
21737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
21747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
21757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return cookieObj;
21767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel  fail:
21777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(cookieObj);
21787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return NULL;
21797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
21817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
21837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_tell(textio *self, PyObject *args)
21847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
21857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res;
21867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *posobj = NULL;
21877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    cookie_type cookie = {0,0,0,0,0};
21887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *next_input;
21897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t chars_to_skip, chars_decoded;
21907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *saved_state = NULL;
21917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    char *input, *input_end;
21927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
21947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_CLOSED(self);
21957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
21967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!self->seekable) {
21977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_IOError,
21987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        "underlying stream is not seekable");
21997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
22007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
22017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!self->telling) {
22027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_IOError,
22037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        "telling position disabled by next() call");
22047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
22057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
22067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_textiowrapper_writeflush(self) < 0)
22087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
22097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyObject_CallMethod((PyObject *)self, "flush", NULL);
22107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
22117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
22127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
22137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    posobj = PyObject_CallMethod(self->buffer, "tell", NULL);
22157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (posobj == NULL)
22167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
22177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->decoder == NULL || self->snapshot == NULL) {
22197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        assert (self->decoded_chars == NULL || PyUnicode_GetSize(self->decoded_chars) == 0);
22207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return posobj;
22217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
22227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#if defined(HAVE_LARGEFILE_SUPPORT)
22247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    cookie.start_pos = PyLong_AsLongLong(posobj);
22257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#else
22267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    cookie.start_pos = PyLong_AsLong(posobj);
22277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel#endif
22287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (PyErr_Occurred())
22297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
22307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Skip backward to the snapshot point (see _read_chunk). */
22327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_Parse(self->snapshot, "(iO)", &cookie.dec_flags, &next_input))
22337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
22347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    assert (PyBytes_Check(next_input));
22367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    cookie.start_pos -= PyBytes_GET_SIZE(next_input);
22387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* How many decoded characters have been used up since the snapshot? */
22407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->decoded_chars_used == 0)  {
22417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* We haven't moved from the snapshot point. */
22427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(posobj);
22437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return textiowrapper_build_cookie(&cookie);
22447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
22457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    chars_to_skip = self->decoded_chars_used;
22477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Starting from the snapshot position, we will walk the decoder
22497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     * forward until it gives us enough decoded characters.
22507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     */
22517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    saved_state = PyObject_CallMethodObjArgs(self->decoder,
22527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                             _PyIO_str_getstate, NULL);
22537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (saved_state == NULL)
22547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
22557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Note our initial start point. */
22577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_textiowrapper_decoder_setstate(self, &cookie) < 0)
22587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        goto fail;
22597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* Feed the decoder one byte at a time.  As we go, note the
22617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     * nearest "safe start point" before the current location
22627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     * (a point where the decoder has nothing buffered, so seek()
22637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     * can safely start from there and advance to this location).
22647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel     */
22657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    chars_decoded = 0;
22667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    input = PyBytes_AS_STRING(next_input);
22677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    input_end = input + PyBytes_GET_SIZE(next_input);
22687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    while (input < input_end) {
22697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *state;
22707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        char *dec_buffer;
22717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_ssize_t dec_buffer_len;
22727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        int dec_flags;
22737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *decoded = PyObject_CallMethod(
22757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->decoder, "decode", "s#", input, (Py_ssize_t)1);
22767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (check_decoded(decoded) < 0)
22777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
22787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        chars_decoded += PyUnicode_GET_SIZE(decoded);
22797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(decoded);
22807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        cookie.bytes_to_feed += 1;
22827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        state = PyObject_CallMethodObjArgs(self->decoder,
22847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                           _PyIO_str_getstate, NULL);
22857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (state == NULL)
22867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
22877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (!PyArg_Parse(state, "(s#i)", &dec_buffer, &dec_buffer_len, &dec_flags)) {
22887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(state);
22897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
22907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
22917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(state);
22927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
22937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (dec_buffer_len == 0 && chars_decoded <= chars_to_skip) {
22947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            /* Decoder buffer is empty, so this is a safe start point. */
22957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            cookie.start_pos += cookie.bytes_to_feed;
22967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            chars_to_skip -= chars_decoded;
22977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            cookie.dec_flags = dec_flags;
22987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            cookie.bytes_to_feed = 0;
22997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            chars_decoded = 0;
23007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
23017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (chars_decoded >= chars_to_skip)
23027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            break;
23037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        input++;
23047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
23057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (input == input_end) {
23067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* We didn't get enough decoded data; signal EOF to get more. */
23077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *decoded = PyObject_CallMethod(
23087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            self->decoder, "decode", "si", "", /* final = */ 1);
23097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (check_decoded(decoded) < 0)
23107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
23117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        chars_decoded += PyUnicode_GET_SIZE(decoded);
23127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(decoded);
23137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        cookie.need_eof = 1;
23147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (chars_decoded < chars_to_skip) {
23167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_SetString(PyExc_IOError,
23177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                            "can't reconstruct logical file position");
23187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto fail;
23197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
23207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
23217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* finally */
23237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(posobj);
23247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyObject_CallMethod(self->decoder, "setstate", "(O)", saved_state);
23257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(saved_state);
23267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
23277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
23287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
23297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    /* The returned cookie corresponds to the last safe start point. */
23317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    cookie.chars_to_skip = Py_SAFE_DOWNCAST(chars_to_skip, Py_ssize_t, int);
23327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return textiowrapper_build_cookie(&cookie);
23337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel  fail:
23357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(posobj);
23367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (saved_state) {
23377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *type, *value, *traceback;
23387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_Fetch(&type, &value, &traceback);
23397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyObject_CallMethod(self->decoder, "setstate", "(O)", saved_state);
23417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        _PyErr_ReplaceException(type, value, traceback);
23427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(saved_state);
23437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_XDECREF(res);
23447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
23457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return NULL;
23467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
23477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
23497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_truncate(textio *self, PyObject *args)
23507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
23517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *pos = Py_None;
23527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res;
23537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self)
23557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
23567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
23577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
23587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyObject_CallMethodObjArgs((PyObject *) self, _PyIO_str_flush, NULL);
23607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
23617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
23627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
23637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_CallMethodObjArgs(self->buffer, _PyIO_str_truncate, pos, NULL);
23657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
23667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
23687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_repr(textio *self)
23697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
23707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *nameobj, *res;
23717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *namerepr = NULL, *encrepr = NULL;
23727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self);
23747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    nameobj = PyObject_GetAttrString((PyObject *) self, "name");
23767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (nameobj == NULL) {
23777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (PyErr_ExceptionMatches(PyExc_Exception))
23787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_Clear();
23797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        else
23807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            goto error;
23817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        encrepr = PyObject_Repr(self->encoding);
23827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyString_FromFormat("<_io.TextIOWrapper encoding=%s>",
23837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                   PyString_AS_STRING(encrepr));
23847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
23857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else {
23867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        encrepr = PyObject_Repr(self->encoding);
23877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        namerepr = PyObject_Repr(nameobj);
23887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyString_FromFormat("<_io.TextIOWrapper name=%s encoding=%s>",
23897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                   PyString_AS_STRING(namerepr),
23907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                   PyString_AS_STRING(encrepr));
23917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(nameobj);
23927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
23937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(namerepr);
23947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(encrepr);
23957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return res;
23967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
23977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielerror:
23987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(namerepr);
23997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_XDECREF(encrepr);
24007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return NULL;
24017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
24027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
24037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
24047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/* Inquiries */
24057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
24067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
24077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_fileno(textio *self, PyObject *args)
24087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
24097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
24107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_CallMethod(self->buffer, "fileno", NULL);
24117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
24127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
24137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
24147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_seekable(textio *self, PyObject *args)
24157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
24167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
24177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_CallMethod(self->buffer, "seekable", NULL);
24187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
24197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
24207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
24217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_readable(textio *self, PyObject *args)
24227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
24237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
24247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_CallMethod(self->buffer, "readable", NULL);
24257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
24267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
24277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
24287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_writable(textio *self, PyObject *args)
24297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
24307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
24317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_CallMethod(self->buffer, "writable", NULL);
24327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
24337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
24347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
24357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_isatty(textio *self, PyObject *args)
24367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
24377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
24387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_CallMethod(self->buffer, "isatty", NULL);
24397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
24407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
24417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
24427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_flush(textio *self, PyObject *args)
24437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
24447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
24457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_CLOSED(self);
24467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->telling = self->seekable;
24477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (_textiowrapper_writeflush(self) < 0)
24487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
24497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_CallMethod(self->buffer, "flush", NULL);
24507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
24517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
24527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
24537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_close(textio *self, PyObject *args)
24547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
24557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res;
24567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    int r;
24577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
24587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
24597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = textiowrapper_closed_get(self, NULL);
24607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL)
24617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
24627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    r = PyObject_IsTrue(res);
24637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_DECREF(res);
24647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (r < 0)
24657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
24667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
24677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (r > 0) {
24687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_RETURN_NONE; /* stream already closed */
24697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
24707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else {
24717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyObject *exc = NULL, *val, *tb;
24727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyObject_CallMethod((PyObject *)self, "flush", NULL);
24737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (res == NULL)
24747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_Fetch(&exc, &val, &tb);
24757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        else
24767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(res);
24777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
24787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        res = PyObject_CallMethod(self->buffer, "close", NULL);
24797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (exc != NULL) {
24807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            _PyErr_ReplaceException(exc, val, tb);
24817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_CLEAR(res);
24827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
24837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return res;
24847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
24857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
24867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
24877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
24887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_iternext(textio *self)
24897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
24907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *line;
24917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
24927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
24937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
24947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->telling = 0;
24957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (Py_TYPE(self) == &PyTextIOWrapper_Type) {
24967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Skip method call overhead for speed */
24977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        line = _textiowrapper_readline(self, -1);
24987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
24997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    else {
25007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        line = PyObject_CallMethodObjArgs((PyObject *)self,
25017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                                           _PyIO_str_readline, NULL);
25027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (line && !PyUnicode_Check(line)) {
25037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_Format(PyExc_IOError,
25047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         "readline() should have returned an str object, "
25057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                         "not '%.200s'", Py_TYPE(line)->tp_name);
25067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_DECREF(line);
25077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
25087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
25097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
25107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
25117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (line == NULL)
25127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
25137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
25147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (PyUnicode_GET_SIZE(line) == 0) {
25157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        /* Reached EOF or would have blocked */
25167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_DECREF(line);
25177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_CLEAR(self->snapshot);
25187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        self->telling = self->seekable;
25197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return NULL;
25207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
25217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
25227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return line;
25237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
25247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
25257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
25267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_name_get(textio *self, void *context)
25277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
25287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
25297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_GetAttrString(self->buffer, "name");
25307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
25317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
25327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
25337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_closed_get(textio *self, void *context)
25347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
25357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
25367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyObject_GetAttr(self->buffer, _PyIO_str_closed);
25377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
25387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
25397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
25407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_newlines_get(textio *self, void *context)
25417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
25427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyObject *res;
25437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
25447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (self->decoder == NULL)
25457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        Py_RETURN_NONE;
25467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    res = PyObject_GetAttr(self->decoder, _PyIO_str_newlines);
25477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (res == NULL) {
25487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
25497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            PyErr_Clear();
25507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            Py_RETURN_NONE;
25517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
25527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        else {
25537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            return NULL;
25547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        }
25557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
25567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return res;
25577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
25587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
25597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
25607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_errors_get(textio *self, void *context)
25617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
25627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_INITIALIZED(self);
25637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_INCREF(self->errors);
25647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return self->errors;
25657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
25667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
25677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyObject *
25687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_chunk_size_get(textio *self, void *context)
25697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
25707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED(self);
25717eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return PyLong_FromSsize_t(self->chunk_size);
25727eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
25737eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
25747eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic int
25757eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanieltextiowrapper_chunk_size_set(textio *self, PyObject *arg, void *context)
25767eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel{
25777eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_ssize_t n;
25787eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    CHECK_ATTACHED_INT(self);
25797eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    n = PyNumber_AsSsize_t(arg, PyExc_TypeError);
25807eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n == -1 && PyErr_Occurred())
25817eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
25827eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    if (n <= 0) {
25837eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        PyErr_SetString(PyExc_ValueError,
25847eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                        "a strictly positive integer is required");
25857eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel        return -1;
25867eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    }
25877eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    self->chunk_size = n;
25887eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    return 0;
25897eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel}
25907eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
25917eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyMethodDef textiowrapper_methods[] = {
25927eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"detach", (PyCFunction)textiowrapper_detach, METH_NOARGS},
25937eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"write", (PyCFunction)textiowrapper_write, METH_VARARGS},
25947eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"read", (PyCFunction)textiowrapper_read, METH_VARARGS},
25957eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"readline", (PyCFunction)textiowrapper_readline, METH_VARARGS},
25967eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"flush", (PyCFunction)textiowrapper_flush, METH_NOARGS},
25977eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"close", (PyCFunction)textiowrapper_close, METH_NOARGS},
25987eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
25997eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"fileno", (PyCFunction)textiowrapper_fileno, METH_NOARGS},
26007eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"seekable", (PyCFunction)textiowrapper_seekable, METH_NOARGS},
26017eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"readable", (PyCFunction)textiowrapper_readable, METH_NOARGS},
26027eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"writable", (PyCFunction)textiowrapper_writable, METH_NOARGS},
26037eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"isatty", (PyCFunction)textiowrapper_isatty, METH_NOARGS},
26047eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
26057eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"seek", (PyCFunction)textiowrapper_seek, METH_VARARGS},
26067eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"tell", (PyCFunction)textiowrapper_tell, METH_NOARGS},
26077eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"truncate", (PyCFunction)textiowrapper_truncate, METH_VARARGS},
26087eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL, NULL}
26097eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
26107eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
26117eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyMemberDef textiowrapper_members[] = {
26127eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"encoding", T_OBJECT, offsetof(textio, encoding), READONLY},
26137eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"buffer", T_OBJECT, offsetof(textio, buffer), READONLY},
26147eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"line_buffering", T_BOOL, offsetof(textio, line_buffering), READONLY},
26157eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL}
26167eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
26177eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
26187eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielstatic PyGetSetDef textiowrapper_getset[] = {
26197eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"name", (getter)textiowrapper_name_get, NULL, NULL},
26207eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"closed", (getter)textiowrapper_closed_get, NULL, NULL},
26217eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel/*    {"mode", (getter)TextIOWrapper_mode_get, NULL, NULL},
26227eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel*/
26237eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"newlines", (getter)textiowrapper_newlines_get, NULL, NULL},
26247eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"errors", (getter)textiowrapper_errors_get, NULL, NULL},
26257eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {"_CHUNK_SIZE", (getter)textiowrapper_chunk_size_get,
26267eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel                    (setter)textiowrapper_chunk_size_set, NULL},
26277eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    {NULL}
26287eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
26297eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel
26307eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDanielPyTypeObject PyTextIOWrapper_Type = {
26317eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyVarObject_HEAD_INIT(NULL, 0)
26327eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    "_io.TextIOWrapper",        /*tp_name*/
26337eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    sizeof(textio), /*tp_basicsize*/
26347eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_itemsize*/
26357eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (destructor)textiowrapper_dealloc, /*tp_dealloc*/
26367eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_print*/
26377eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_getattr*/
26387eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tps_etattr*/
26397eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_compare */
26407eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (reprfunc)textiowrapper_repr,/*tp_repr*/
26417eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_number*/
26427eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_sequence*/
26437eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_mapping*/
26447eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_hash */
26457eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_call*/
26467eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_str*/
26477eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_getattro*/
26487eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_setattro*/
26497eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /*tp_as_buffer*/
26507eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
26517eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel            | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
26527eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    textiowrapper_doc,          /* tp_doc */
26537eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (traverseproc)textiowrapper_traverse, /* tp_traverse */
26547eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (inquiry)textiowrapper_clear, /* tp_clear */
26557eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_richcompare */
26567eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    offsetof(textio, weakreflist), /*tp_weaklistoffset*/
26577eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_iter */
26587eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (iternextfunc)textiowrapper_iternext, /* tp_iternext */
26597eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    textiowrapper_methods,      /* tp_methods */
26607eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    textiowrapper_members,      /* tp_members */
26617eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    textiowrapper_getset,       /* tp_getset */
26627eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_base */
26637eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_dict */
26647eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_descr_get */
26657eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_descr_set */
26667eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    offsetof(textio, dict), /*tp_dictoffset*/
26677eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    (initproc)textiowrapper_init, /* tp_init */
26687eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    0,                          /* tp_alloc */
26697eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel    PyType_GenericNew,          /* tp_new */
26707eb75bccb5dacb658c63db1a9a980950c3d54d42Daryl McDaniel};
2671