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