LCOV - code coverage report
Current view: top level - Modules/_io - stringio.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit 5e6661bce9] Lines: 161 393 41.0 %
Date: 2023-03-20 08:15:36 Functions: 13 27 48.1 %
Branches: 92 322 28.6 %

           Branch data     Line data    Source code
       1                 :            : #define PY_SSIZE_T_CLEAN
       2                 :            : #include "Python.h"
       3                 :            : #include <stddef.h>               // offsetof()
       4                 :            : #include "pycore_object.h"
       5                 :            : #include "_iomodule.h"
       6                 :            : 
       7                 :            : /* Implementation note: the buffer is always at least one character longer
       8                 :            :    than the enclosed string, for proper functioning of _PyIO_find_line_ending.
       9                 :            : */
      10                 :            : 
      11                 :            : #define STATE_REALIZED 1
      12                 :            : #define STATE_ACCUMULATING 2
      13                 :            : 
      14                 :            : /*[clinic input]
      15                 :            : module _io
      16                 :            : class _io.StringIO "stringio *" "clinic_state()->PyStringIO_Type"
      17                 :            : [clinic start generated code]*/
      18                 :            : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=2693eada0658d470]*/
      19                 :            : 
      20                 :            : typedef struct {
      21                 :            :     PyObject_HEAD
      22                 :            :     Py_UCS4 *buf;
      23                 :            :     Py_ssize_t pos;
      24                 :            :     Py_ssize_t string_size;
      25                 :            :     size_t buf_size;
      26                 :            : 
      27                 :            :     /* The stringio object can be in two states: accumulating or realized.
      28                 :            :        In accumulating state, the internal buffer contains nothing and
      29                 :            :        the contents are given by the embedded _PyUnicodeWriter structure.
      30                 :            :        In realized state, the internal buffer is meaningful and the
      31                 :            :        _PyUnicodeWriter is destroyed.
      32                 :            :     */
      33                 :            :     int state;
      34                 :            :     _PyUnicodeWriter writer;
      35                 :            : 
      36                 :            :     char ok; /* initialized? */
      37                 :            :     char closed;
      38                 :            :     char readuniversal;
      39                 :            :     char readtranslate;
      40                 :            :     PyObject *decoder;
      41                 :            :     PyObject *readnl;
      42                 :            :     PyObject *writenl;
      43                 :            : 
      44                 :            :     PyObject *dict;
      45                 :            :     PyObject *weakreflist;
      46                 :            :     _PyIO_State *module_state;
      47                 :            : } stringio;
      48                 :            : 
      49                 :            : static int _io_StringIO___init__(PyObject *self, PyObject *args, PyObject *kwargs);
      50                 :            : 
      51                 :            : #define CHECK_INITIALIZED(self) \
      52                 :            :     if (self->ok <= 0) { \
      53                 :            :         PyErr_SetString(PyExc_ValueError, \
      54                 :            :             "I/O operation on uninitialized object"); \
      55                 :            :         return NULL; \
      56                 :            :     }
      57                 :            : 
      58                 :            : #define CHECK_CLOSED(self) \
      59                 :            :     if (self->closed) { \
      60                 :            :         PyErr_SetString(PyExc_ValueError, \
      61                 :            :             "I/O operation on closed file"); \
      62                 :            :         return NULL; \
      63                 :            :     }
      64                 :            : 
      65                 :            : #define ENSURE_REALIZED(self) \
      66                 :            :     if (realize(self) < 0) { \
      67                 :            :         return NULL; \
      68                 :            :     }
      69                 :            : 
      70                 :            : 
      71                 :            : /* Internal routine for changing the size, in terms of characters, of the
      72                 :            :    buffer of StringIO objects.  The caller should ensure that the 'size'
      73                 :            :    argument is non-negative.  Returns 0 on success, -1 otherwise. */
      74                 :            : static int
      75                 :        125 : resize_buffer(stringio *self, size_t size)
      76                 :            : {
      77                 :            :     /* Here, unsigned types are used to avoid dealing with signed integer
      78                 :            :        overflow, which is undefined in C. */
      79                 :        125 :     size_t alloc = self->buf_size;
      80                 :        125 :     Py_UCS4 *new_buf = NULL;
      81                 :            : 
      82                 :            :     assert(self->buf != NULL);
      83                 :            : 
      84                 :            :     /* Reserve one more char for line ending detection. */
      85                 :        125 :     size = size + 1;
      86                 :            :     /* For simplicity, stay in the range of the signed type. Anyway, Python
      87                 :            :        doesn't allow strings to be longer than this. */
      88         [ -  + ]:        125 :     if (size > PY_SSIZE_T_MAX)
      89                 :          0 :         goto overflow;
      90                 :            : 
      91         [ +  + ]:        125 :     if (size < alloc / 2) {
      92                 :            :         /* Major downsize; resize down to exact size. */
      93                 :         38 :         alloc = size + 1;
      94                 :            :     }
      95         [ +  + ]:         87 :     else if (size < alloc) {
      96                 :            :         /* Within allocated size; quick exit */
      97                 :          1 :         return 0;
      98                 :            :     }
      99         [ +  + ]:         86 :     else if (size <= alloc * 1.125) {
     100                 :            :         /* Moderate upsize; overallocate similar to list_resize() */
     101         [ +  + ]:         37 :         alloc = size + (size >> 3) + (size < 9 ? 3 : 6);
     102                 :            :     }
     103                 :            :     else {
     104                 :            :         /* Major upsize; resize up to exact size */
     105                 :         49 :         alloc = size + 1;
     106                 :            :     }
     107                 :            : 
     108         [ -  + ]:        124 :     if (alloc > PY_SIZE_MAX / sizeof(Py_UCS4))
     109                 :          0 :         goto overflow;
     110                 :        124 :     new_buf = (Py_UCS4 *)PyMem_Realloc(self->buf, alloc * sizeof(Py_UCS4));
     111         [ -  + ]:        124 :     if (new_buf == NULL) {
     112                 :          0 :         PyErr_NoMemory();
     113                 :          0 :         return -1;
     114                 :            :     }
     115                 :        124 :     self->buf_size = alloc;
     116                 :        124 :     self->buf = new_buf;
     117                 :            : 
     118                 :        124 :     return 0;
     119                 :            : 
     120                 :          0 :   overflow:
     121                 :          0 :     PyErr_SetString(PyExc_OverflowError,
     122                 :            :                     "new buffer size too large");
     123                 :          0 :     return -1;
     124                 :            : }
     125                 :            : 
     126                 :            : static PyObject *
     127                 :         19 : make_intermediate(stringio *self)
     128                 :            : {
     129                 :         19 :     PyObject *intermediate = _PyUnicodeWriter_Finish(&self->writer);
     130                 :         19 :     self->state = STATE_REALIZED;
     131         [ -  + ]:         19 :     if (intermediate == NULL)
     132                 :          0 :         return NULL;
     133                 :            : 
     134                 :         19 :     _PyUnicodeWriter_Init(&self->writer);
     135                 :         19 :     self->writer.overallocate = 1;
     136         [ -  + ]:         19 :     if (_PyUnicodeWriter_WriteStr(&self->writer, intermediate)) {
     137                 :          0 :         Py_DECREF(intermediate);
     138                 :          0 :         return NULL;
     139                 :            :     }
     140                 :         19 :     self->state = STATE_ACCUMULATING;
     141                 :         19 :     return intermediate;
     142                 :            : }
     143                 :            : 
     144                 :            : static int
     145                 :         38 : realize(stringio *self)
     146                 :            : {
     147                 :            :     Py_ssize_t len;
     148                 :            :     PyObject *intermediate;
     149                 :            : 
     150         [ +  + ]:         38 :     if (self->state == STATE_REALIZED)
     151                 :         37 :         return 0;
     152                 :            :     assert(self->state == STATE_ACCUMULATING);
     153                 :          1 :     self->state = STATE_REALIZED;
     154                 :            : 
     155                 :          1 :     intermediate = _PyUnicodeWriter_Finish(&self->writer);
     156         [ -  + ]:          1 :     if (intermediate == NULL)
     157                 :          0 :         return -1;
     158                 :            : 
     159                 :            :     /* Append the intermediate string to the internal buffer.
     160                 :            :        The length should be equal to the current cursor position.
     161                 :            :      */
     162                 :          1 :     len = PyUnicode_GET_LENGTH(intermediate);
     163         [ -  + ]:          1 :     if (resize_buffer(self, len) < 0) {
     164                 :          0 :         Py_DECREF(intermediate);
     165                 :          0 :         return -1;
     166                 :            :     }
     167         [ -  + ]:          1 :     if (!PyUnicode_AsUCS4(intermediate, self->buf, len, 0)) {
     168                 :          0 :         Py_DECREF(intermediate);
     169                 :          0 :         return -1;
     170                 :            :     }
     171                 :            : 
     172                 :          1 :     Py_DECREF(intermediate);
     173                 :          1 :     return 0;
     174                 :            : }
     175                 :            : 
     176                 :            : /* Internal routine for writing a whole PyUnicode object to the buffer of a
     177                 :            :    StringIO object. Returns 0 on success, or -1 on error. */
     178                 :            : static Py_ssize_t
     179                 :        112 : write_str(stringio *self, PyObject *obj)
     180                 :            : {
     181                 :            :     Py_ssize_t len;
     182                 :        112 :     PyObject *decoded = NULL;
     183                 :            : 
     184                 :            :     assert(self->buf != NULL);
     185                 :            :     assert(self->pos >= 0);
     186                 :            : 
     187         [ -  + ]:        112 :     if (self->decoder != NULL) {
     188                 :          0 :         decoded = _PyIncrementalNewlineDecoder_decode(
     189                 :            :             self->decoder, obj, 1 /* always final */);
     190                 :            :     }
     191                 :            :     else {
     192                 :        112 :         decoded = Py_NewRef(obj);
     193                 :            :     }
     194         [ -  + ]:        112 :     if (self->writenl) {
     195                 :          0 :         PyObject *translated = PyUnicode_Replace(
     196                 :            :             decoded, &_Py_STR(newline), self->writenl, -1);
     197                 :          0 :         Py_SETREF(decoded, translated);
     198                 :            :     }
     199         [ -  + ]:        112 :     if (decoded == NULL)
     200                 :          0 :         return -1;
     201                 :            : 
     202                 :            :     assert(PyUnicode_Check(decoded));
     203         [ -  + ]:        112 :     if (PyUnicode_READY(decoded)) {
     204                 :          0 :         Py_DECREF(decoded);
     205                 :          0 :         return -1;
     206                 :            :     }
     207                 :        112 :     len = PyUnicode_GET_LENGTH(decoded);
     208                 :            :     assert(len >= 0);
     209                 :            : 
     210                 :            :     /* This overflow check is not strictly necessary. However, it avoids us to
     211                 :            :        deal with funky things like comparing an unsigned and a signed
     212                 :            :        integer. */
     213         [ -  + ]:        112 :     if (self->pos > PY_SSIZE_T_MAX - len) {
     214                 :          0 :         PyErr_SetString(PyExc_OverflowError,
     215                 :            :                         "new position too large");
     216                 :          0 :         goto fail;
     217                 :            :     }
     218                 :            : 
     219         [ +  + ]:        112 :     if (self->state == STATE_ACCUMULATING) {
     220         [ +  - ]:         38 :         if (self->string_size == self->pos) {
     221         [ -  + ]:         38 :             if (_PyUnicodeWriter_WriteStr(&self->writer, decoded))
     222                 :          0 :                 goto fail;
     223                 :         38 :             goto success;
     224                 :            :         }
     225         [ #  # ]:          0 :         if (realize(self))
     226                 :          0 :             goto fail;
     227                 :            :     }
     228                 :            : 
     229         [ +  - ]:         74 :     if (self->pos + len > self->string_size) {
     230         [ -  + ]:         74 :         if (resize_buffer(self, self->pos + len) < 0)
     231                 :          0 :             goto fail;
     232                 :            :     }
     233                 :            : 
     234         [ -  + ]:         74 :     if (self->pos > self->string_size) {
     235                 :            :         /* In case of overseek, pad with null bytes the buffer region between
     236                 :            :            the end of stream and the current position.
     237                 :            : 
     238                 :            :           0   lo      string_size                           hi
     239                 :            :           |   |<---used--->|<----------available----------->|
     240                 :            :           |   |            <--to pad-->|<---to write--->    |
     241                 :            :           0   buf                   position
     242                 :            : 
     243                 :            :         */
     244                 :          0 :         memset(self->buf + self->string_size, '\0',
     245                 :          0 :                (self->pos - self->string_size) * sizeof(Py_UCS4));
     246                 :            :     }
     247                 :            : 
     248                 :            :     /* Copy the data to the internal buffer, overwriting some of the
     249                 :            :        existing data if self->pos < self->string_size. */
     250         [ -  + ]:         74 :     if (!PyUnicode_AsUCS4(decoded,
     251                 :         74 :                           self->buf + self->pos,
     252                 :         74 :                           self->buf_size - self->pos,
     253                 :            :                           0))
     254                 :          0 :         goto fail;
     255                 :            : 
     256                 :         74 : success:
     257                 :            :     /* Set the new length of the internal string if it has changed. */
     258                 :        112 :     self->pos += len;
     259         [ +  - ]:        112 :     if (self->string_size < self->pos)
     260                 :        112 :         self->string_size = self->pos;
     261                 :            : 
     262                 :        112 :     Py_DECREF(decoded);
     263                 :        112 :     return 0;
     264                 :            : 
     265                 :          0 : fail:
     266                 :          0 :     Py_XDECREF(decoded);
     267                 :          0 :     return -1;
     268                 :            : }
     269                 :            : 
     270                 :            : /*[clinic input]
     271                 :            : _io.StringIO.getvalue
     272                 :            : 
     273                 :            : Retrieve the entire contents of the object.
     274                 :            : [clinic start generated code]*/
     275                 :            : 
     276                 :            : static PyObject *
     277                 :         65 : _io_StringIO_getvalue_impl(stringio *self)
     278                 :            : /*[clinic end generated code: output=27b6a7bfeaebce01 input=d23cb81d6791cf88]*/
     279                 :            : {
     280         [ -  + ]:         65 :     CHECK_INITIALIZED(self);
     281         [ -  + ]:         65 :     CHECK_CLOSED(self);
     282         [ +  + ]:         65 :     if (self->state == STATE_ACCUMULATING)
     283                 :         19 :         return make_intermediate(self);
     284                 :         46 :     return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, self->buf,
     285                 :            :                                      self->string_size);
     286                 :            : }
     287                 :            : 
     288                 :            : /*[clinic input]
     289                 :            : _io.StringIO.tell
     290                 :            : 
     291                 :            : Tell the current file position.
     292                 :            : [clinic start generated code]*/
     293                 :            : 
     294                 :            : static PyObject *
     295                 :          0 : _io_StringIO_tell_impl(stringio *self)
     296                 :            : /*[clinic end generated code: output=2e87ac67b116c77b input=ec866ebaff02f405]*/
     297                 :            : {
     298         [ #  # ]:          0 :     CHECK_INITIALIZED(self);
     299         [ #  # ]:          0 :     CHECK_CLOSED(self);
     300                 :          0 :     return PyLong_FromSsize_t(self->pos);
     301                 :            : }
     302                 :            : 
     303                 :            : /*[clinic input]
     304                 :            : _io.StringIO.read
     305                 :            :     size: Py_ssize_t(accept={int, NoneType}) = -1
     306                 :            :     /
     307                 :            : 
     308                 :            : Read at most size characters, returned as a string.
     309                 :            : 
     310                 :            : If the argument is negative or omitted, read until EOF
     311                 :            : is reached. Return an empty string at EOF.
     312                 :            : [clinic start generated code]*/
     313                 :            : 
     314                 :            : static PyObject *
     315                 :          0 : _io_StringIO_read_impl(stringio *self, Py_ssize_t size)
     316                 :            : /*[clinic end generated code: output=ae8cf6002f71626c input=0921093383dfb92d]*/
     317                 :            : {
     318                 :            :     Py_ssize_t n;
     319                 :            :     Py_UCS4 *output;
     320                 :            : 
     321         [ #  # ]:          0 :     CHECK_INITIALIZED(self);
     322         [ #  # ]:          0 :     CHECK_CLOSED(self);
     323                 :            : 
     324                 :            :     /* adjust invalid sizes */
     325                 :          0 :     n = self->string_size - self->pos;
     326   [ #  #  #  # ]:          0 :     if (size < 0 || size > n) {
     327                 :          0 :         size = n;
     328         [ #  # ]:          0 :         if (size < 0)
     329                 :          0 :             size = 0;
     330                 :            :     }
     331                 :            : 
     332                 :            :     /* Optimization for seek(0); read() */
     333   [ #  #  #  #  :          0 :     if (self->state == STATE_ACCUMULATING && self->pos == 0 && size == n) {
                   #  # ]
     334                 :          0 :         PyObject *result = make_intermediate(self);
     335                 :          0 :         self->pos = self->string_size;
     336                 :          0 :         return result;
     337                 :            :     }
     338                 :            : 
     339         [ #  # ]:          0 :     ENSURE_REALIZED(self);
     340                 :          0 :     output = self->buf + self->pos;
     341                 :          0 :     self->pos += size;
     342                 :          0 :     return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, output, size);
     343                 :            : }
     344                 :            : 
     345                 :            : /* Internal helper, used by stringio_readline and stringio_iternext */
     346                 :            : static PyObject *
     347                 :          0 : _stringio_readline(stringio *self, Py_ssize_t limit)
     348                 :            : {
     349                 :            :     Py_UCS4 *start, *end, old_char;
     350                 :            :     Py_ssize_t len, consumed;
     351                 :            : 
     352                 :            :     /* In case of overseek, return the empty string */
     353         [ #  # ]:          0 :     if (self->pos >= self->string_size)
     354                 :          0 :         return PyUnicode_New(0, 0);
     355                 :            : 
     356                 :          0 :     start = self->buf + self->pos;
     357   [ #  #  #  # ]:          0 :     if (limit < 0 || limit > self->string_size - self->pos)
     358                 :          0 :         limit = self->string_size - self->pos;
     359                 :            : 
     360                 :          0 :     end = start + limit;
     361                 :          0 :     old_char = *end;
     362                 :          0 :     *end = '\0';
     363                 :          0 :     len = _PyIO_find_line_ending(
     364                 :          0 :         self->readtranslate, self->readuniversal, self->readnl,
     365                 :            :         PyUnicode_4BYTE_KIND, (char*)start, (char*)end, &consumed);
     366                 :          0 :     *end = old_char;
     367                 :            :     /* If we haven't found any line ending, we just return everything
     368                 :            :        (`consumed` is ignored). */
     369         [ #  # ]:          0 :     if (len < 0)
     370                 :          0 :         len = limit;
     371                 :          0 :     self->pos += len;
     372                 :          0 :     return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, start, len);
     373                 :            : }
     374                 :            : 
     375                 :            : /*[clinic input]
     376                 :            : _io.StringIO.readline
     377                 :            :     size: Py_ssize_t(accept={int, NoneType}) = -1
     378                 :            :     /
     379                 :            : 
     380                 :            : Read until newline or EOF.
     381                 :            : 
     382                 :            : Returns an empty string if EOF is hit immediately.
     383                 :            : [clinic start generated code]*/
     384                 :            : 
     385                 :            : static PyObject *
     386                 :          0 : _io_StringIO_readline_impl(stringio *self, Py_ssize_t size)
     387                 :            : /*[clinic end generated code: output=cabd6452f1b7e85d input=a5bd70bf682aa276]*/
     388                 :            : {
     389         [ #  # ]:          0 :     CHECK_INITIALIZED(self);
     390         [ #  # ]:          0 :     CHECK_CLOSED(self);
     391         [ #  # ]:          0 :     ENSURE_REALIZED(self);
     392                 :            : 
     393                 :          0 :     return _stringio_readline(self, size);
     394                 :            : }
     395                 :            : 
     396                 :            : static PyObject *
     397                 :          0 : stringio_iternext(stringio *self)
     398                 :            : {
     399                 :            :     PyObject *line;
     400                 :            : 
     401         [ #  # ]:          0 :     CHECK_INITIALIZED(self);
     402         [ #  # ]:          0 :     CHECK_CLOSED(self);
     403         [ #  # ]:          0 :     ENSURE_REALIZED(self);
     404                 :            : 
     405         [ #  # ]:          0 :     if (Py_IS_TYPE(self, self->module_state->PyStringIO_Type)) {
     406                 :            :         /* Skip method call overhead for speed */
     407                 :          0 :         line = _stringio_readline(self, -1);
     408                 :            :     }
     409                 :            :     else {
     410                 :            :         /* XXX is subclassing StringIO really supported? */
     411                 :          0 :         line = PyObject_CallMethodNoArgs((PyObject *)self,
     412                 :            :                                              &_Py_ID(readline));
     413   [ #  #  #  # ]:          0 :         if (line && !PyUnicode_Check(line)) {
     414                 :          0 :             PyErr_Format(PyExc_OSError,
     415                 :            :                          "readline() should have returned a str object, "
     416                 :          0 :                          "not '%.200s'", Py_TYPE(line)->tp_name);
     417                 :          0 :             Py_DECREF(line);
     418                 :          0 :             return NULL;
     419                 :            :         }
     420                 :            :     }
     421                 :            : 
     422         [ #  # ]:          0 :     if (line == NULL)
     423                 :          0 :         return NULL;
     424                 :            : 
     425         [ #  # ]:          0 :     if (PyUnicode_GET_LENGTH(line) == 0) {
     426                 :            :         /* Reached EOF */
     427                 :          0 :         Py_DECREF(line);
     428                 :          0 :         return NULL;
     429                 :            :     }
     430                 :            : 
     431                 :          0 :     return line;
     432                 :            : }
     433                 :            : 
     434                 :            : /*[clinic input]
     435                 :            : _io.StringIO.truncate
     436                 :            :     pos as size: Py_ssize_t(accept={int, NoneType}, c_default="self->pos") = None
     437                 :            :     /
     438                 :            : 
     439                 :            : Truncate size to pos.
     440                 :            : 
     441                 :            : The pos argument defaults to the current file position, as
     442                 :            : returned by tell().  The current file position is unchanged.
     443                 :            : Returns the new absolute position.
     444                 :            : [clinic start generated code]*/
     445                 :            : 
     446                 :            : static PyObject *
     447                 :         56 : _io_StringIO_truncate_impl(stringio *self, Py_ssize_t size)
     448                 :            : /*[clinic end generated code: output=eb3aef8e06701365 input=5505cff90ca48b96]*/
     449                 :            : {
     450         [ -  + ]:         56 :     CHECK_INITIALIZED(self);
     451         [ -  + ]:         56 :     CHECK_CLOSED(self);
     452                 :            : 
     453         [ -  + ]:         56 :     if (size < 0) {
     454                 :          0 :         PyErr_Format(PyExc_ValueError,
     455                 :            :                      "Negative size value %zd", size);
     456                 :          0 :         return NULL;
     457                 :            :     }
     458                 :            : 
     459         [ +  + ]:         56 :     if (size < self->string_size) {
     460         [ -  + ]:         38 :         ENSURE_REALIZED(self);
     461         [ -  + ]:         38 :         if (resize_buffer(self, size) < 0)
     462                 :          0 :             return NULL;
     463                 :         38 :         self->string_size = size;
     464                 :            :     }
     465                 :            : 
     466                 :         56 :     return PyLong_FromSsize_t(size);
     467                 :            : }
     468                 :            : 
     469                 :            : /*[clinic input]
     470                 :            : _io.StringIO.seek
     471                 :            :     pos: Py_ssize_t
     472                 :            :     whence: int = 0
     473                 :            :     /
     474                 :            : 
     475                 :            : Change stream position.
     476                 :            : 
     477                 :            : Seek to character offset pos relative to position indicated by whence:
     478                 :            :     0  Start of stream (the default).  pos should be >= 0;
     479                 :            :     1  Current position - pos must be 0;
     480                 :            :     2  End of stream - pos must be 0.
     481                 :            : Returns the new absolute position.
     482                 :            : [clinic start generated code]*/
     483                 :            : 
     484                 :            : static PyObject *
     485                 :         56 : _io_StringIO_seek_impl(stringio *self, Py_ssize_t pos, int whence)
     486                 :            : /*[clinic end generated code: output=e9e0ac9a8ae71c25 input=e3855b24e7cae06a]*/
     487                 :            : {
     488         [ -  + ]:         56 :     CHECK_INITIALIZED(self);
     489         [ -  + ]:         56 :     CHECK_CLOSED(self);
     490                 :            : 
     491   [ -  +  -  -  :         56 :     if (whence != 0 && whence != 1 && whence != 2) {
                   -  - ]
     492                 :          0 :         PyErr_Format(PyExc_ValueError,
     493                 :            :                      "Invalid whence (%i, should be 0, 1 or 2)", whence);
     494                 :          0 :         return NULL;
     495                 :            :     }
     496   [ -  +  -  - ]:         56 :     else if (pos < 0 && whence == 0) {
     497                 :          0 :         PyErr_Format(PyExc_ValueError,
     498                 :            :                      "Negative seek position %zd", pos);
     499                 :          0 :         return NULL;
     500                 :            :     }
     501   [ -  +  -  - ]:         56 :     else if (whence != 0 && pos != 0) {
     502                 :          0 :         PyErr_SetString(PyExc_OSError,
     503                 :            :                         "Can't do nonzero cur-relative seeks");
     504                 :          0 :         return NULL;
     505                 :            :     }
     506                 :            : 
     507                 :            :     /* whence = 0: offset relative to beginning of the string.
     508                 :            :        whence = 1: no change to current position.
     509                 :            :        whence = 2: change position to end of file. */
     510         [ -  + ]:         56 :     if (whence == 1) {
     511                 :          0 :         pos = self->pos;
     512                 :            :     }
     513         [ -  + ]:         56 :     else if (whence == 2) {
     514                 :          0 :         pos = self->string_size;
     515                 :            :     }
     516                 :            : 
     517                 :         56 :     self->pos = pos;
     518                 :            : 
     519                 :         56 :     return PyLong_FromSsize_t(self->pos);
     520                 :            : }
     521                 :            : 
     522                 :            : /*[clinic input]
     523                 :            : _io.StringIO.write
     524                 :            :     s as obj: object
     525                 :            :     /
     526                 :            : 
     527                 :            : Write string to file.
     528                 :            : 
     529                 :            : Returns the number of characters written, which is always equal to
     530                 :            : the length of the string.
     531                 :            : [clinic start generated code]*/
     532                 :            : 
     533                 :            : static PyObject *
     534                 :        148 : _io_StringIO_write(stringio *self, PyObject *obj)
     535                 :            : /*[clinic end generated code: output=0deaba91a15b94da input=cf96f3b16586e669]*/
     536                 :            : {
     537                 :            :     Py_ssize_t size;
     538                 :            : 
     539         [ -  + ]:        148 :     CHECK_INITIALIZED(self);
     540         [ -  + ]:        148 :     if (!PyUnicode_Check(obj)) {
     541                 :          0 :         PyErr_Format(PyExc_TypeError, "string argument expected, got '%s'",
     542                 :          0 :                      Py_TYPE(obj)->tp_name);
     543                 :          0 :         return NULL;
     544                 :            :     }
     545         [ -  + ]:        148 :     if (PyUnicode_READY(obj))
     546                 :          0 :         return NULL;
     547         [ -  + ]:        148 :     CHECK_CLOSED(self);
     548                 :        148 :     size = PyUnicode_GET_LENGTH(obj);
     549                 :            : 
     550   [ +  +  -  + ]:        148 :     if (size > 0 && write_str(self, obj) < 0)
     551                 :          0 :         return NULL;
     552                 :            : 
     553                 :        148 :     return PyLong_FromSsize_t(size);
     554                 :            : }
     555                 :            : 
     556                 :            : /*[clinic input]
     557                 :            : _io.StringIO.close
     558                 :            : 
     559                 :            : Close the IO object.
     560                 :            : 
     561                 :            : Attempting any further operation after the object is closed
     562                 :            : will raise a ValueError.
     563                 :            : 
     564                 :            : This method has no effect if the file is already closed.
     565                 :            : [clinic start generated code]*/
     566                 :            : 
     567                 :            : static PyObject *
     568                 :          1 : _io_StringIO_close_impl(stringio *self)
     569                 :            : /*[clinic end generated code: output=04399355cbe518f1 input=cbc10b45f35d6d46]*/
     570                 :            : {
     571                 :          1 :     self->closed = 1;
     572                 :            :     /* Free up some memory */
     573         [ -  + ]:          1 :     if (resize_buffer(self, 0) < 0)
     574                 :          0 :         return NULL;
     575                 :          1 :     _PyUnicodeWriter_Dealloc(&self->writer);
     576         [ +  - ]:          1 :     Py_CLEAR(self->readnl);
     577         [ -  + ]:          1 :     Py_CLEAR(self->writenl);
     578         [ -  + ]:          1 :     Py_CLEAR(self->decoder);
     579                 :          1 :     Py_RETURN_NONE;
     580                 :            : }
     581                 :            : 
     582                 :            : static int
     583                 :          0 : stringio_traverse(stringio *self, visitproc visit, void *arg)
     584                 :            : {
     585   [ #  #  #  # ]:          0 :     Py_VISIT(Py_TYPE(self));
     586   [ #  #  #  # ]:          0 :     Py_VISIT(self->dict);
     587                 :          0 :     return 0;
     588                 :            : }
     589                 :            : 
     590                 :            : static int
     591                 :          0 : stringio_clear(stringio *self)
     592                 :            : {
     593         [ #  # ]:          0 :     Py_CLEAR(self->dict);
     594                 :          0 :     return 0;
     595                 :            : }
     596                 :            : 
     597                 :            : static void
     598                 :         11 : stringio_dealloc(stringio *self)
     599                 :            : {
     600                 :         11 :     PyTypeObject *tp = Py_TYPE(self);
     601                 :         11 :     _PyObject_GC_UNTRACK(self);
     602                 :         11 :     self->ok = 0;
     603         [ +  - ]:         11 :     if (self->buf) {
     604                 :         11 :         PyMem_Free(self->buf);
     605                 :         11 :         self->buf = NULL;
     606                 :            :     }
     607                 :         11 :     _PyUnicodeWriter_Dealloc(&self->writer);
     608         [ +  + ]:         11 :     Py_CLEAR(self->readnl);
     609         [ -  + ]:         11 :     Py_CLEAR(self->writenl);
     610         [ -  + ]:         11 :     Py_CLEAR(self->decoder);
     611         [ +  + ]:         11 :     Py_CLEAR(self->dict);
     612         [ -  + ]:         11 :     if (self->weakreflist != NULL) {
     613                 :          0 :         PyObject_ClearWeakRefs((PyObject *) self);
     614                 :            :     }
     615                 :         11 :     tp->tp_free(self);
     616                 :         11 :     Py_DECREF(tp);
     617                 :         11 : }
     618                 :            : 
     619                 :            : static PyObject *
     620                 :         11 : stringio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     621                 :            : {
     622                 :            :     stringio *self;
     623                 :            : 
     624                 :            :     assert(type != NULL && type->tp_alloc != NULL);
     625                 :         11 :     self = (stringio *)type->tp_alloc(type, 0);
     626         [ -  + ]:         11 :     if (self == NULL)
     627                 :          0 :         return NULL;
     628                 :            : 
     629                 :            :     /* tp_alloc initializes all the fields to zero. So we don't have to
     630                 :            :        initialize them here. */
     631                 :            : 
     632                 :         11 :     self->buf = (Py_UCS4 *)PyMem_Malloc(0);
     633         [ -  + ]:         11 :     if (self->buf == NULL) {
     634                 :          0 :         Py_DECREF(self);
     635                 :          0 :         return PyErr_NoMemory();
     636                 :            :     }
     637                 :            : 
     638                 :         11 :     return (PyObject *)self;
     639                 :            : }
     640                 :            : 
     641                 :            : /*[clinic input]
     642                 :            : _io.StringIO.__init__
     643                 :            :     initial_value as value: object(c_default="NULL") = ''
     644                 :            :     newline as newline_obj: object(c_default="NULL") = '\n'
     645                 :            : 
     646                 :            : Text I/O implementation using an in-memory buffer.
     647                 :            : 
     648                 :            : The initial_value argument sets the value of object.  The newline
     649                 :            : argument is like the one of TextIOWrapper's constructor.
     650                 :            : [clinic start generated code]*/
     651                 :            : 
     652                 :            : static int
     653                 :         11 : _io_StringIO___init___impl(stringio *self, PyObject *value,
     654                 :            :                            PyObject *newline_obj)
     655                 :            : /*[clinic end generated code: output=a421ea023b22ef4e input=cee2d9181b2577a3]*/
     656                 :            : {
     657                 :         11 :     const char *newline = "\n";
     658                 :            :     Py_ssize_t value_len;
     659                 :            : 
     660                 :            :     /* Parse the newline argument. We only want to allow unicode objects or
     661                 :            :        None. */
     662         [ -  + ]:         11 :     if (newline_obj == Py_None) {
     663                 :          0 :         newline = NULL;
     664                 :            :     }
     665         [ -  + ]:         11 :     else if (newline_obj) {
     666         [ #  # ]:          0 :         if (!PyUnicode_Check(newline_obj)) {
     667                 :          0 :             PyErr_Format(PyExc_TypeError,
     668                 :            :                          "newline must be str or None, not %.200s",
     669                 :          0 :                          Py_TYPE(newline_obj)->tp_name);
     670                 :          0 :             return -1;
     671                 :            :         }
     672                 :          0 :         newline = PyUnicode_AsUTF8(newline_obj);
     673         [ #  # ]:          0 :         if (newline == NULL)
     674                 :          0 :             return -1;
     675                 :            :     }
     676                 :            : 
     677   [ +  -  +  - ]:         11 :     if (newline && newline[0] != '\0'
     678   [ +  -  -  + ]:         11 :         && !(newline[0] == '\n' && newline[1] == '\0')
     679   [ #  #  #  # ]:          0 :         && !(newline[0] == '\r' && newline[1] == '\0')
     680   [ #  #  #  #  :          0 :         && !(newline[0] == '\r' && newline[1] == '\n' && newline[2] == '\0')) {
                   #  # ]
     681                 :          0 :         PyErr_Format(PyExc_ValueError,
     682                 :            :                      "illegal newline value: %R", newline_obj);
     683                 :          0 :         return -1;
     684                 :            :     }
     685   [ -  +  -  -  :         11 :     if (value && value != Py_None && !PyUnicode_Check(value)) {
                   -  - ]
     686                 :          0 :         PyErr_Format(PyExc_TypeError,
     687                 :            :                      "initial_value must be str or None, not %.200s",
     688                 :          0 :                      Py_TYPE(value)->tp_name);
     689                 :          0 :         return -1;
     690                 :            :     }
     691                 :            : 
     692                 :         11 :     self->ok = 0;
     693                 :            : 
     694                 :         11 :     _PyUnicodeWriter_Dealloc(&self->writer);
     695         [ -  + ]:         11 :     Py_CLEAR(self->readnl);
     696         [ -  + ]:         11 :     Py_CLEAR(self->writenl);
     697         [ -  + ]:         11 :     Py_CLEAR(self->decoder);
     698                 :            : 
     699                 :            :     assert((newline != NULL && newline_obj != Py_None) ||
     700                 :            :            (newline == NULL && newline_obj == Py_None));
     701                 :            : 
     702         [ +  - ]:         11 :     if (newline) {
     703                 :         11 :         self->readnl = PyUnicode_FromString(newline);
     704         [ -  + ]:         11 :         if (self->readnl == NULL)
     705                 :          0 :             return -1;
     706                 :            :     }
     707   [ +  -  -  + ]:         11 :     self->readuniversal = (newline == NULL || newline[0] == '\0');
     708                 :         11 :     self->readtranslate = (newline == NULL);
     709                 :            :     /* If newline == "", we don't translate anything.
     710                 :            :        If newline == "\n" or newline == None, we translate to "\n", which is
     711                 :            :        a no-op.
     712                 :            :        (for newline == None, TextIOWrapper translates to os.linesep, but it
     713                 :            :        is pointless for StringIO)
     714                 :            :     */
     715   [ +  -  -  + ]:         11 :     if (newline != NULL && newline[0] == '\r') {
     716                 :          0 :         self->writenl = Py_NewRef(self->readnl);
     717                 :            :     }
     718                 :            : 
     719         [ -  + ]:         11 :     if (self->readuniversal) {
     720                 :          0 :         self->decoder = PyObject_CallFunctionObjArgs(
     721                 :            :             (PyObject *)&PyIncrementalNewlineDecoder_Type,
     722         [ #  # ]:          0 :             Py_None, self->readtranslate ? Py_True : Py_False, NULL);
     723         [ #  # ]:          0 :         if (self->decoder == NULL)
     724                 :          0 :             return -1;
     725                 :            :     }
     726                 :            : 
     727                 :            :     /* Now everything is set up, resize buffer to size of initial value,
     728                 :            :        and copy it */
     729                 :         11 :     self->string_size = 0;
     730   [ -  +  -  - ]:         11 :     if (value && value != Py_None)
     731                 :          0 :         value_len = PyUnicode_GetLength(value);
     732                 :            :     else
     733                 :         11 :         value_len = 0;
     734         [ -  + ]:         11 :     if (value_len > 0) {
     735                 :            :         /* This is a heuristic, for newline translation might change
     736                 :            :            the string length. */
     737         [ #  # ]:          0 :         if (resize_buffer(self, 0) < 0)
     738                 :          0 :             return -1;
     739                 :          0 :         self->state = STATE_REALIZED;
     740                 :          0 :         self->pos = 0;
     741         [ #  # ]:          0 :         if (write_str(self, value) < 0)
     742                 :          0 :             return -1;
     743                 :            :     }
     744                 :            :     else {
     745                 :            :         /* Empty stringio object, we can start by accumulating */
     746         [ -  + ]:         11 :         if (resize_buffer(self, 0) < 0)
     747                 :          0 :             return -1;
     748                 :         11 :         _PyUnicodeWriter_Init(&self->writer);
     749                 :         11 :         self->writer.overallocate = 1;
     750                 :         11 :         self->state = STATE_ACCUMULATING;
     751                 :            :     }
     752                 :         11 :     self->pos = 0;
     753                 :         11 :     self->module_state = find_io_state_by_def(Py_TYPE(self));
     754                 :         11 :     self->closed = 0;
     755                 :         11 :     self->ok = 1;
     756                 :         11 :     return 0;
     757                 :            : }
     758                 :            : 
     759                 :            : /* Properties and pseudo-properties */
     760                 :            : 
     761                 :            : /*[clinic input]
     762                 :            : _io.StringIO.readable
     763                 :            : 
     764                 :            : Returns True if the IO object can be read.
     765                 :            : [clinic start generated code]*/
     766                 :            : 
     767                 :            : static PyObject *
     768                 :          0 : _io_StringIO_readable_impl(stringio *self)
     769                 :            : /*[clinic end generated code: output=b19d44dd8b1ceb99 input=39ce068b224c21ad]*/
     770                 :            : {
     771         [ #  # ]:          0 :     CHECK_INITIALIZED(self);
     772         [ #  # ]:          0 :     CHECK_CLOSED(self);
     773                 :          0 :     Py_RETURN_TRUE;
     774                 :            : }
     775                 :            : 
     776                 :            : /*[clinic input]
     777                 :            : _io.StringIO.writable
     778                 :            : 
     779                 :            : Returns True if the IO object can be written.
     780                 :            : [clinic start generated code]*/
     781                 :            : 
     782                 :            : static PyObject *
     783                 :          0 : _io_StringIO_writable_impl(stringio *self)
     784                 :            : /*[clinic end generated code: output=13e4dd77187074ca input=7a691353aac38835]*/
     785                 :            : {
     786         [ #  # ]:          0 :     CHECK_INITIALIZED(self);
     787         [ #  # ]:          0 :     CHECK_CLOSED(self);
     788                 :          0 :     Py_RETURN_TRUE;
     789                 :            : }
     790                 :            : 
     791                 :            : /*[clinic input]
     792                 :            : _io.StringIO.seekable
     793                 :            : 
     794                 :            : Returns True if the IO object can be seeked.
     795                 :            : [clinic start generated code]*/
     796                 :            : 
     797                 :            : static PyObject *
     798                 :          0 : _io_StringIO_seekable_impl(stringio *self)
     799                 :            : /*[clinic end generated code: output=4d20b4641c756879 input=4c606d05b32952e6]*/
     800                 :            : {
     801         [ #  # ]:          0 :     CHECK_INITIALIZED(self);
     802         [ #  # ]:          0 :     CHECK_CLOSED(self);
     803                 :          0 :     Py_RETURN_TRUE;
     804                 :            : }
     805                 :            : 
     806                 :            : /* Pickling support.
     807                 :            : 
     808                 :            :    The implementation of __getstate__ is similar to the one for BytesIO,
     809                 :            :    except that we also save the newline parameter. For __setstate__ and unlike
     810                 :            :    BytesIO, we call __init__ to restore the object's state. Doing so allows us
     811                 :            :    to avoid decoding the complex newline state while keeping the object
     812                 :            :    representation compact.
     813                 :            : 
     814                 :            :    See comment in bytesio.c regarding why only pickle protocols and onward are
     815                 :            :    supported.
     816                 :            : */
     817                 :            : 
     818                 :            : static PyObject *
     819                 :          0 : stringio_getstate(stringio *self, PyObject *Py_UNUSED(ignored))
     820                 :            : {
     821                 :          0 :     PyObject *initvalue = _io_StringIO_getvalue_impl(self);
     822                 :            :     PyObject *dict;
     823                 :            :     PyObject *state;
     824                 :            : 
     825         [ #  # ]:          0 :     if (initvalue == NULL)
     826                 :          0 :         return NULL;
     827         [ #  # ]:          0 :     if (self->dict == NULL) {
     828                 :          0 :         dict = Py_NewRef(Py_None);
     829                 :            :     }
     830                 :            :     else {
     831                 :          0 :         dict = PyDict_Copy(self->dict);
     832         [ #  # ]:          0 :         if (dict == NULL) {
     833                 :          0 :             Py_DECREF(initvalue);
     834                 :          0 :             return NULL;
     835                 :            :         }
     836                 :            :     }
     837                 :            : 
     838                 :          0 :     state = Py_BuildValue("(OOnN)", initvalue,
     839         [ #  # ]:          0 :                           self->readnl ? self->readnl : Py_None,
     840                 :            :                           self->pos, dict);
     841                 :          0 :     Py_DECREF(initvalue);
     842                 :          0 :     return state;
     843                 :            : }
     844                 :            : 
     845                 :            : static PyObject *
     846                 :          0 : stringio_setstate(stringio *self, PyObject *state)
     847                 :            : {
     848                 :            :     PyObject *initarg;
     849                 :            :     PyObject *position_obj;
     850                 :            :     PyObject *dict;
     851                 :            :     Py_ssize_t pos;
     852                 :            : 
     853                 :            :     assert(state != NULL);
     854         [ #  # ]:          0 :     CHECK_CLOSED(self);
     855                 :            : 
     856                 :            :     /* We allow the state tuple to be longer than 4, because we may need
     857                 :            :        someday to extend the object's state without breaking
     858                 :            :        backward-compatibility. */
     859   [ #  #  #  # ]:          0 :     if (!PyTuple_Check(state) || PyTuple_GET_SIZE(state) < 4) {
     860                 :          0 :         PyErr_Format(PyExc_TypeError,
     861                 :            :                      "%.200s.__setstate__ argument should be 4-tuple, got %.200s",
     862                 :          0 :                      Py_TYPE(self)->tp_name, Py_TYPE(state)->tp_name);
     863                 :          0 :         return NULL;
     864                 :            :     }
     865                 :            : 
     866                 :            :     /* Initialize the object's state. */
     867                 :          0 :     initarg = PyTuple_GetSlice(state, 0, 2);
     868         [ #  # ]:          0 :     if (initarg == NULL)
     869                 :          0 :         return NULL;
     870         [ #  # ]:          0 :     if (_io_StringIO___init__((PyObject *)self, initarg, NULL) < 0) {
     871                 :          0 :         Py_DECREF(initarg);
     872                 :          0 :         return NULL;
     873                 :            :     }
     874                 :          0 :     Py_DECREF(initarg);
     875                 :            : 
     876                 :            :     /* Restore the buffer state. Even if __init__ did initialize the buffer,
     877                 :            :        we have to initialize it again since __init__ may translate the
     878                 :            :        newlines in the initial_value string. We clearly do not want that
     879                 :            :        because the string value in the state tuple has already been translated
     880                 :            :        once by __init__. So we do not take any chance and replace object's
     881                 :            :        buffer completely. */
     882                 :            :     {
     883                 :            :         PyObject *item;
     884                 :            :         Py_UCS4 *buf;
     885                 :            :         Py_ssize_t bufsize;
     886                 :            : 
     887                 :          0 :         item = PyTuple_GET_ITEM(state, 0);
     888                 :          0 :         buf = PyUnicode_AsUCS4Copy(item);
     889         [ #  # ]:          0 :         if (buf == NULL)
     890                 :          0 :             return NULL;
     891                 :          0 :         bufsize = PyUnicode_GET_LENGTH(item);
     892                 :            : 
     893         [ #  # ]:          0 :         if (resize_buffer(self, bufsize) < 0) {
     894                 :          0 :             PyMem_Free(buf);
     895                 :          0 :             return NULL;
     896                 :            :         }
     897                 :          0 :         memcpy(self->buf, buf, bufsize * sizeof(Py_UCS4));
     898                 :          0 :         PyMem_Free(buf);
     899                 :          0 :         self->string_size = bufsize;
     900                 :            :     }
     901                 :            : 
     902                 :            :     /* Set carefully the position value. Alternatively, we could use the seek
     903                 :            :        method instead of modifying self->pos directly to better protect the
     904                 :            :        object internal state against erroneous (or malicious) inputs. */
     905                 :          0 :     position_obj = PyTuple_GET_ITEM(state, 2);
     906         [ #  # ]:          0 :     if (!PyLong_Check(position_obj)) {
     907                 :          0 :         PyErr_Format(PyExc_TypeError,
     908                 :            :                      "third item of state must be an integer, got %.200s",
     909                 :          0 :                      Py_TYPE(position_obj)->tp_name);
     910                 :          0 :         return NULL;
     911                 :            :     }
     912                 :          0 :     pos = PyLong_AsSsize_t(position_obj);
     913   [ #  #  #  # ]:          0 :     if (pos == -1 && PyErr_Occurred())
     914                 :          0 :         return NULL;
     915         [ #  # ]:          0 :     if (pos < 0) {
     916                 :          0 :         PyErr_SetString(PyExc_ValueError,
     917                 :            :                         "position value cannot be negative");
     918                 :          0 :         return NULL;
     919                 :            :     }
     920                 :          0 :     self->pos = pos;
     921                 :            : 
     922                 :            :     /* Set the dictionary of the instance variables. */
     923                 :          0 :     dict = PyTuple_GET_ITEM(state, 3);
     924         [ #  # ]:          0 :     if (dict != Py_None) {
     925         [ #  # ]:          0 :         if (!PyDict_Check(dict)) {
     926                 :          0 :             PyErr_Format(PyExc_TypeError,
     927                 :            :                          "fourth item of state should be a dict, got a %.200s",
     928                 :          0 :                          Py_TYPE(dict)->tp_name);
     929                 :          0 :             return NULL;
     930                 :            :         }
     931         [ #  # ]:          0 :         if (self->dict) {
     932                 :            :             /* Alternatively, we could replace the internal dictionary
     933                 :            :                completely. However, it seems more practical to just update it. */
     934         [ #  # ]:          0 :             if (PyDict_Update(self->dict, dict) < 0)
     935                 :          0 :                 return NULL;
     936                 :            :         }
     937                 :            :         else {
     938                 :          0 :             self->dict = Py_NewRef(dict);
     939                 :            :         }
     940                 :            :     }
     941                 :            : 
     942                 :          0 :     Py_RETURN_NONE;
     943                 :            : }
     944                 :            : 
     945                 :            : 
     946                 :            : static PyObject *
     947                 :          1 : stringio_closed(stringio *self, void *context)
     948                 :            : {
     949         [ -  + ]:          1 :     CHECK_INITIALIZED(self);
     950                 :          1 :     return PyBool_FromLong(self->closed);
     951                 :            : }
     952                 :            : 
     953                 :            : static PyObject *
     954                 :          0 : stringio_line_buffering(stringio *self, void *context)
     955                 :            : {
     956         [ #  # ]:          0 :     CHECK_INITIALIZED(self);
     957         [ #  # ]:          0 :     CHECK_CLOSED(self);
     958                 :          0 :     Py_RETURN_FALSE;
     959                 :            : }
     960                 :            : 
     961                 :            : static PyObject *
     962                 :          0 : stringio_newlines(stringio *self, void *context)
     963                 :            : {
     964         [ #  # ]:          0 :     CHECK_INITIALIZED(self);
     965         [ #  # ]:          0 :     CHECK_CLOSED(self);
     966         [ #  # ]:          0 :     if (self->decoder == NULL)
     967                 :          0 :         Py_RETURN_NONE;
     968                 :          0 :     return PyObject_GetAttr(self->decoder, &_Py_ID(newlines));
     969                 :            : }
     970                 :            : 
     971                 :            : #define clinic_state() (find_io_state_by_def(Py_TYPE(self)))
     972                 :            : #include "clinic/stringio.c.h"
     973                 :            : #undef clinic_state
     974                 :            : 
     975                 :            : static struct PyMethodDef stringio_methods[] = {
     976                 :            :     _IO_STRINGIO_CLOSE_METHODDEF
     977                 :            :     _IO_STRINGIO_GETVALUE_METHODDEF
     978                 :            :     _IO_STRINGIO_READ_METHODDEF
     979                 :            :     _IO_STRINGIO_READLINE_METHODDEF
     980                 :            :     _IO_STRINGIO_TELL_METHODDEF
     981                 :            :     _IO_STRINGIO_TRUNCATE_METHODDEF
     982                 :            :     _IO_STRINGIO_SEEK_METHODDEF
     983                 :            :     _IO_STRINGIO_WRITE_METHODDEF
     984                 :            : 
     985                 :            :     _IO_STRINGIO_SEEKABLE_METHODDEF
     986                 :            :     _IO_STRINGIO_READABLE_METHODDEF
     987                 :            :     _IO_STRINGIO_WRITABLE_METHODDEF
     988                 :            : 
     989                 :            :     {"__getstate__", (PyCFunction)stringio_getstate, METH_NOARGS},
     990                 :            :     {"__setstate__", (PyCFunction)stringio_setstate, METH_O},
     991                 :            :     {NULL, NULL}        /* sentinel */
     992                 :            : };
     993                 :            : 
     994                 :            : static PyGetSetDef stringio_getset[] = {
     995                 :            :     {"closed",         (getter)stringio_closed,         NULL, NULL},
     996                 :            :     {"newlines",       (getter)stringio_newlines,       NULL, NULL},
     997                 :            :     /*  (following comments straight off of the original Python wrapper:)
     998                 :            :         XXX Cruft to support the TextIOWrapper API. This would only
     999                 :            :         be meaningful if StringIO supported the buffer attribute.
    1000                 :            :         Hopefully, a better solution, than adding these pseudo-attributes,
    1001                 :            :         will be found.
    1002                 :            :     */
    1003                 :            :     {"line_buffering", (getter)stringio_line_buffering, NULL, NULL},
    1004                 :            :     {NULL}
    1005                 :            : };
    1006                 :            : 
    1007                 :            : static struct PyMemberDef stringio_members[] = {
    1008                 :            :     {"__weaklistoffset__", T_PYSSIZET, offsetof(stringio, weakreflist), READONLY},
    1009                 :            :     {"__dictoffset__", T_PYSSIZET, offsetof(stringio, dict), READONLY},
    1010                 :            :     {NULL},
    1011                 :            : };
    1012                 :            : 
    1013                 :            : static PyType_Slot stringio_slots[] = {
    1014                 :            :     {Py_tp_dealloc, stringio_dealloc},
    1015                 :            :     {Py_tp_doc, (void *)_io_StringIO___init____doc__},
    1016                 :            :     {Py_tp_traverse, stringio_traverse},
    1017                 :            :     {Py_tp_clear, stringio_clear},
    1018                 :            :     {Py_tp_iternext, stringio_iternext},
    1019                 :            :     {Py_tp_methods, stringio_methods},
    1020                 :            :     {Py_tp_members, stringio_members},
    1021                 :            :     {Py_tp_getset, stringio_getset},
    1022                 :            :     {Py_tp_init, _io_StringIO___init__},
    1023                 :            :     {Py_tp_new, stringio_new},
    1024                 :            :     {0, NULL},
    1025                 :            : };
    1026                 :            : 
    1027                 :            : PyType_Spec stringio_spec = {
    1028                 :            :     .name = "_io.StringIO",
    1029                 :            :     .basicsize = sizeof(stringio),
    1030                 :            :     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
    1031                 :            :               Py_TPFLAGS_IMMUTABLETYPE),
    1032                 :            :     .slots = stringio_slots,
    1033                 :            : };

Generated by: LCOV version 1.14