Coverage Report

Created: 2026-08-28 06:28

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