No issues found
1 #define PY_SSIZE_T_CLEAN
2 #include "Python.h"
3 #include "structmember.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 typedef struct {
11 PyObject_HEAD
12 Py_UNICODE *buf;
13 Py_ssize_t pos;
14 Py_ssize_t string_size;
15 size_t buf_size;
16
17 char ok; /* initialized? */
18 char closed;
19 char readuniversal;
20 char readtranslate;
21 PyObject *decoder;
22 PyObject *readnl;
23 PyObject *writenl;
24
25 PyObject *dict;
26 PyObject *weakreflist;
27 } stringio;
28
29 #define CHECK_INITIALIZED(self) \
30 if (self->ok <= 0) { \
31 PyErr_SetString(PyExc_ValueError, \
32 "I/O operation on uninitialized object"); \
33 return NULL; \
34 }
35
36 #define CHECK_CLOSED(self) \
37 if (self->closed) { \
38 PyErr_SetString(PyExc_ValueError, \
39 "I/O operation on closed file"); \
40 return NULL; \
41 }
42
43 PyDoc_STRVAR(stringio_doc,
44 "Text I/O implementation using an in-memory buffer.\n"
45 "\n"
46 "The initial_value argument sets the value of object. The newline\n"
47 "argument is like the one of TextIOWrapper's constructor.");
48
49
50 /* Internal routine for changing the size, in terms of characters, of the
51 buffer of StringIO objects. The caller should ensure that the 'size'
52 argument is non-negative. Returns 0 on success, -1 otherwise. */
53 static int
54 resize_buffer(stringio *self, size_t size)
55 {
56 /* Here, unsigned types are used to avoid dealing with signed integer
57 overflow, which is undefined in C. */
58 size_t alloc = self->buf_size;
59 Py_UNICODE *new_buf = NULL;
60
61 assert(self->buf != NULL);
62
63 /* Reserve one more char for line ending detection. */
64 size = size + 1;
65 /* For simplicity, stay in the range of the signed type. Anyway, Python
66 doesn't allow strings to be longer than this. */
67 if (size > PY_SSIZE_T_MAX)
68 goto overflow;
69
70 if (size < alloc / 2) {
71 /* Major downsize; resize down to exact size. */
72 alloc = size + 1;
73 }
74 else if (size < alloc) {
75 /* Within allocated size; quick exit */
76 return 0;
77 }
78 else if (size <= alloc * 1.125) {
79 /* Moderate upsize; overallocate similar to list_resize() */
80 alloc = size + (size >> 3) + (size < 9 ? 3 : 6);
81 }
82 else {
83 /* Major upsize; resize up to exact size */
84 alloc = size + 1;
85 }
86
87 if (alloc > ((size_t)-1) / sizeof(Py_UNICODE))
88 goto overflow;
89 new_buf = (Py_UNICODE *)PyMem_Realloc(self->buf,
90 alloc * sizeof(Py_UNICODE));
91 if (new_buf == NULL) {
92 PyErr_NoMemory();
93 return -1;
94 }
95 self->buf_size = alloc;
96 self->buf = new_buf;
97
98 return 0;
99
100 overflow:
101 PyErr_SetString(PyExc_OverflowError,
102 "new buffer size too large");
103 return -1;
104 }
105
106 /* Internal routine for writing a whole PyUnicode object to the buffer of a
107 StringIO object. Returns 0 on success, or -1 on error. */
108 static Py_ssize_t
109 write_str(stringio *self, PyObject *obj)
110 {
111 Py_UNICODE *str;
112 Py_ssize_t len;
113 PyObject *decoded = NULL;
114 assert(self->buf != NULL);
115 assert(self->pos >= 0);
116
117 if (self->decoder != NULL) {
118 decoded = _PyIncrementalNewlineDecoder_decode(
119 self->decoder, obj, 1 /* always final */);
120 }
121 else {
122 decoded = obj;
123 Py_INCREF(decoded);
124 }
125 if (self->writenl) {
126 PyObject *translated = PyUnicode_Replace(
127 decoded, _PyIO_str_nl, self->writenl, -1);
128 Py_DECREF(decoded);
129 decoded = translated;
130 }
131 if (decoded == NULL)
132 return -1;
133
134 assert(PyUnicode_Check(decoded));
135 str = PyUnicode_AS_UNICODE(decoded);
136 len = PyUnicode_GET_SIZE(decoded);
137
138 assert(len >= 0);
139
140 /* This overflow check is not strictly necessary. However, it avoids us to
141 deal with funky things like comparing an unsigned and a signed
142 integer. */
143 if (self->pos > PY_SSIZE_T_MAX - len) {
144 PyErr_SetString(PyExc_OverflowError,
145 "new position too large");
146 goto fail;
147 }
148 if (self->pos + len > self->string_size) {
149 if (resize_buffer(self, self->pos + len) < 0)
150 goto fail;
151 }
152
153 if (self->pos > self->string_size) {
154 /* In case of overseek, pad with null bytes the buffer region between
155 the end of stream and the current position.
156
157 0 lo string_size hi
158 | |<---used--->|<----------available----------->|
159 | | <--to pad-->|<---to write---> |
160 0 buf position
161
162 */
163 memset(self->buf + self->string_size, '\0',
164 (self->pos - self->string_size) * sizeof(Py_UNICODE));
165 }
166
167 /* Copy the data to the internal buffer, overwriting some of the
168 existing data if self->pos < self->string_size. */
169 memcpy(self->buf + self->pos, str, len * sizeof(Py_UNICODE));
170 self->pos += len;
171
172 /* Set the new length of the internal string if it has changed. */
173 if (self->string_size < self->pos) {
174 self->string_size = self->pos;
175 }
176
177 Py_DECREF(decoded);
178 return 0;
179
180 fail:
181 Py_XDECREF(decoded);
182 return -1;
183 }
184
185 PyDoc_STRVAR(stringio_getvalue_doc,
186 "Retrieve the entire contents of the object.");
187
188 static PyObject *
189 stringio_getvalue(stringio *self)
190 {
191 CHECK_INITIALIZED(self);
192 CHECK_CLOSED(self);
193 return PyUnicode_FromUnicode(self->buf, self->string_size);
194 }
195
196 PyDoc_STRVAR(stringio_tell_doc,
197 "Tell the current file position.");
198
199 static PyObject *
200 stringio_tell(stringio *self)
201 {
202 CHECK_INITIALIZED(self);
203 CHECK_CLOSED(self);
204 return PyLong_FromSsize_t(self->pos);
205 }
206
207 PyDoc_STRVAR(stringio_read_doc,
208 "Read at most n characters, returned as a string.\n"
209 "\n"
210 "If the argument is negative or omitted, read until EOF\n"
211 "is reached. Return an empty string at EOF.\n");
212
213 static PyObject *
214 stringio_read(stringio *self, PyObject *args)
215 {
216 Py_ssize_t size, n;
217 Py_UNICODE *output;
218 PyObject *arg = Py_None;
219
220 CHECK_INITIALIZED(self);
221 if (!PyArg_ParseTuple(args, "|O:read", &arg))
222 return NULL;
223 CHECK_CLOSED(self);
224
225 if (PyNumber_Check(arg)) {
226 size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
227 if (size == -1 && PyErr_Occurred())
228 return NULL;
229 }
230 else if (arg == Py_None) {
231 /* Read until EOF is reached, by default. */
232 size = -1;
233 }
234 else {
235 PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
236 Py_TYPE(arg)->tp_name);
237 return NULL;
238 }
239
240 /* adjust invalid sizes */
241 n = self->string_size - self->pos;
242 if (size < 0 || size > n) {
243 size = n;
244 if (size < 0)
245 size = 0;
246 }
247
248 output = self->buf + self->pos;
249 self->pos += size;
250 return PyUnicode_FromUnicode(output, size);
251 }
252
253 /* Internal helper, used by stringio_readline and stringio_iternext */
254 static PyObject *
255 _stringio_readline(stringio *self, Py_ssize_t limit)
256 {
257 Py_UNICODE *start, *end, old_char;
258 Py_ssize_t len, consumed;
259
260 /* In case of overseek, return the empty string */
261 if (self->pos >= self->string_size)
262 return PyUnicode_FromString("");
263
264 start = self->buf + self->pos;
265 if (limit < 0 || limit > self->string_size - self->pos)
266 limit = self->string_size - self->pos;
267
268 end = start + limit;
269 old_char = *end;
270 *end = '\0';
271 len = _PyIO_find_line_ending(
272 self->readtranslate, self->readuniversal, self->readnl,
273 start, end, &consumed);
274 *end = old_char;
275 /* If we haven't found any line ending, we just return everything
276 (`consumed` is ignored). */
277 if (len < 0)
278 len = limit;
279 self->pos += len;
280 return PyUnicode_FromUnicode(start, len);
281 }
282
283 PyDoc_STRVAR(stringio_readline_doc,
284 "Read until newline or EOF.\n"
285 "\n"
286 "Returns an empty string if EOF is hit immediately.\n");
287
288 static PyObject *
289 stringio_readline(stringio *self, PyObject *args)
290 {
291 PyObject *arg = Py_None;
292 Py_ssize_t limit = -1;
293
294 CHECK_INITIALIZED(self);
295 if (!PyArg_ParseTuple(args, "|O:readline", &arg))
296 return NULL;
297 CHECK_CLOSED(self);
298
299 if (PyNumber_Check(arg)) {
300 limit = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
301 if (limit == -1 && PyErr_Occurred())
302 return NULL;
303 }
304 else if (arg != Py_None) {
305 PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
306 Py_TYPE(arg)->tp_name);
307 return NULL;
308 }
309 return _stringio_readline(self, limit);
310 }
311
312 static PyObject *
313 stringio_iternext(stringio *self)
314 {
315 PyObject *line;
316
317 CHECK_INITIALIZED(self);
318 CHECK_CLOSED(self);
319
320 if (Py_TYPE(self) == &PyStringIO_Type) {
321 /* Skip method call overhead for speed */
322 line = _stringio_readline(self, -1);
323 }
324 else {
325 /* XXX is subclassing StringIO really supported? */
326 line = PyObject_CallMethodObjArgs((PyObject *)self,
327 _PyIO_str_readline, NULL);
328 if (line && !PyUnicode_Check(line)) {
329 PyErr_Format(PyExc_IOError,
330 "readline() should have returned an str object, "
331 "not '%.200s'", Py_TYPE(line)->tp_name);
332 Py_DECREF(line);
333 return NULL;
334 }
335 }
336
337 if (line == NULL)
338 return NULL;
339
340 if (PyUnicode_GET_SIZE(line) == 0) {
341 /* Reached EOF */
342 Py_DECREF(line);
343 return NULL;
344 }
345
346 return line;
347 }
348
349 PyDoc_STRVAR(stringio_truncate_doc,
350 "Truncate size to pos.\n"
351 "\n"
352 "The pos argument defaults to the current file position, as\n"
353 "returned by tell(). The current file position is unchanged.\n"
354 "Returns the new absolute position.\n");
355
356 static PyObject *
357 stringio_truncate(stringio *self, PyObject *args)
358 {
359 Py_ssize_t size;
360 PyObject *arg = Py_None;
361
362 CHECK_INITIALIZED(self);
363 if (!PyArg_ParseTuple(args, "|O:truncate", &arg))
364 return NULL;
365 CHECK_CLOSED(self);
366
367 if (PyNumber_Check(arg)) {
368 size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
369 if (size == -1 && PyErr_Occurred())
370 return NULL;
371 }
372 else if (arg == Py_None) {
373 /* Truncate to current position if no argument is passed. */
374 size = self->pos;
375 }
376 else {
377 PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
378 Py_TYPE(arg)->tp_name);
379 return NULL;
380 }
381
382 if (size < 0) {
383 PyErr_Format(PyExc_ValueError,
384 "Negative size value %zd", size);
385 return NULL;
386 }
387
388 if (size < self->string_size) {
389 if (resize_buffer(self, size) < 0)
390 return NULL;
391 self->string_size = size;
392 }
393
394 return PyLong_FromSsize_t(size);
395 }
396
397 PyDoc_STRVAR(stringio_seek_doc,
398 "Change stream position.\n"
399 "\n"
400 "Seek to character offset pos relative to position indicated by whence:\n"
401 " 0 Start of stream (the default). pos should be >= 0;\n"
402 " 1 Current position - pos must be 0;\n"
403 " 2 End of stream - pos must be 0.\n"
404 "Returns the new absolute position.\n");
405
406 static PyObject *
407 stringio_seek(stringio *self, PyObject *args)
408 {
409 PyObject *posobj;
410 Py_ssize_t pos;
411 int mode = 0;
412
413 CHECK_INITIALIZED(self);
414 if (!PyArg_ParseTuple(args, "O|i:seek", &posobj, &mode))
415 return NULL;
416
417 pos = PyNumber_AsSsize_t(posobj, PyExc_OverflowError);
418 if (pos == -1 && PyErr_Occurred())
419 return NULL;
420
421 CHECK_CLOSED(self);
422
423 if (mode != 0 && mode != 1 && mode != 2) {
424 PyErr_Format(PyExc_ValueError,
425 "Invalid whence (%i, should be 0, 1 or 2)", mode);
426 return NULL;
427 }
428 else if (pos < 0 && mode == 0) {
429 PyErr_Format(PyExc_ValueError,
430 "Negative seek position %zd", pos);
431 return NULL;
432 }
433 else if (mode != 0 && pos != 0) {
434 PyErr_SetString(PyExc_IOError,
435 "Can't do nonzero cur-relative seeks");
436 return NULL;
437 }
438
439 /* mode 0: offset relative to beginning of the string.
440 mode 1: no change to current position.
441 mode 2: change position to end of file. */
442 if (mode == 1) {
443 pos = self->pos;
444 }
445 else if (mode == 2) {
446 pos = self->string_size;
447 }
448
449 self->pos = pos;
450
451 return PyLong_FromSsize_t(self->pos);
452 }
453
454 PyDoc_STRVAR(stringio_write_doc,
455 "Write string to file.\n"
456 "\n"
457 "Returns the number of characters written, which is always equal to\n"
458 "the length of the string.\n");
459
460 static PyObject *
461 stringio_write(stringio *self, PyObject *obj)
462 {
463 Py_ssize_t size;
464
465 CHECK_INITIALIZED(self);
466 if (!PyUnicode_Check(obj)) {
467 PyErr_Format(PyExc_TypeError, "unicode argument expected, got '%s'",
468 Py_TYPE(obj)->tp_name);
469 return NULL;
470 }
471 CHECK_CLOSED(self);
472 size = PyUnicode_GET_SIZE(obj);
473
474 if (size > 0 && write_str(self, obj) < 0)
475 return NULL;
476
477 return PyLong_FromSsize_t(size);
478 }
479
480 PyDoc_STRVAR(stringio_close_doc,
481 "Close the IO object. Attempting any further operation after the\n"
482 "object is closed will raise a ValueError.\n"
483 "\n"
484 "This method has no effect if the file is already closed.\n");
485
486 static PyObject *
487 stringio_close(stringio *self)
488 {
489 self->closed = 1;
490 /* Free up some memory */
491 if (resize_buffer(self, 0) < 0)
492 return NULL;
493 Py_CLEAR(self->readnl);
494 Py_CLEAR(self->writenl);
495 Py_CLEAR(self->decoder);
496 Py_RETURN_NONE;
497 }
498
499 static int
500 stringio_traverse(stringio *self, visitproc visit, void *arg)
501 {
502 Py_VISIT(self->dict);
503 return 0;
504 }
505
506 static int
507 stringio_clear(stringio *self)
508 {
509 Py_CLEAR(self->dict);
510 return 0;
511 }
512
513 static void
514 stringio_dealloc(stringio *self)
515 {
516 _PyObject_GC_UNTRACK(self);
517 self->ok = 0;
518 if (self->buf) {
519 PyMem_Free(self->buf);
520 self->buf = NULL;
521 }
522 Py_CLEAR(self->readnl);
523 Py_CLEAR(self->writenl);
524 Py_CLEAR(self->decoder);
525 Py_CLEAR(self->dict);
526 if (self->weakreflist != NULL)
527 PyObject_ClearWeakRefs((PyObject *) self);
528 Py_TYPE(self)->tp_free(self);
529 }
530
531 static PyObject *
532 stringio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
533 {
534 stringio *self;
535
536 assert(type != NULL && type->tp_alloc != NULL);
537 self = (stringio *)type->tp_alloc(type, 0);
538 if (self == NULL)
539 return NULL;
540
541 /* tp_alloc initializes all the fields to zero. So we don't have to
542 initialize them here. */
543
544 self->buf = (Py_UNICODE *)PyMem_Malloc(0);
545 if (self->buf == NULL) {
546 Py_DECREF(self);
547 return PyErr_NoMemory();
548 }
549
550 return (PyObject *)self;
551 }
552
553 static int
554 stringio_init(stringio *self, PyObject *args, PyObject *kwds)
555 {
556 char *kwlist[] = {"initial_value", "newline", NULL};
557 PyObject *value = NULL;
558 char *newline = "\n";
559
560 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oz:__init__", kwlist,
561 &value, &newline))
562 return -1;
563
564 if (newline && newline[0] != '\0'
565 && !(newline[0] == '\n' && newline[1] == '\0')
566 && !(newline[0] == '\r' && newline[1] == '\0')
567 && !(newline[0] == '\r' && newline[1] == '\n' && newline[2] == '\0')) {
568 PyErr_Format(PyExc_ValueError,
569 "illegal newline value: %s", newline);
570 return -1;
571 }
572 if (value && value != Py_None && !PyUnicode_Check(value)) {
573 PyErr_Format(PyExc_TypeError,
574 "initial_value must be unicode or None, not %.200s",
575 Py_TYPE(value)->tp_name);
576 return -1;
577 }
578
579 self->ok = 0;
580
581 Py_CLEAR(self->readnl);
582 Py_CLEAR(self->writenl);
583 Py_CLEAR(self->decoder);
584
585 if (newline) {
586 self->readnl = PyString_FromString(newline);
587 if (self->readnl == NULL)
588 return -1;
589 }
590 self->readuniversal = (newline == NULL || newline[0] == '\0');
591 self->readtranslate = (newline == NULL);
592 /* If newline == "", we don't translate anything.
593 If newline == "\n" or newline == None, we translate to "\n", which is
594 a no-op.
595 (for newline == None, TextIOWrapper translates to os.sepline, but it
596 is pointless for StringIO)
597 */
598 if (newline != NULL && newline[0] == '\r') {
599 self->writenl = PyUnicode_FromString(newline);
600 }
601
602 if (self->readuniversal) {
603 self->decoder = PyObject_CallFunction(
604 (PyObject *)&PyIncrementalNewlineDecoder_Type,
605 "Oi", Py_None, (int) self->readtranslate);
606 if (self->decoder == NULL)
607 return -1;
608 }
609
610 /* Now everything is set up, resize buffer to size of initial value,
611 and copy it */
612 self->string_size = 0;
613 if (value && value != Py_None) {
614 Py_ssize_t len = PyUnicode_GetSize(value);
615 /* This is a heuristic, for newline translation might change
616 the string length. */
617 if (resize_buffer(self, len) < 0)
618 return -1;
619 self->pos = 0;
620 if (write_str(self, value) < 0)
621 return -1;
622 }
623 else {
624 if (resize_buffer(self, 0) < 0)
625 return -1;
626 }
627 self->pos = 0;
628
629 self->closed = 0;
630 self->ok = 1;
631 return 0;
632 }
633
634 /* Properties and pseudo-properties */
635 static PyObject *
636 stringio_seekable(stringio *self, PyObject *args)
637 {
638 CHECK_INITIALIZED(self);
639 Py_RETURN_TRUE;
640 }
641
642 static PyObject *
643 stringio_readable(stringio *self, PyObject *args)
644 {
645 CHECK_INITIALIZED(self);
646 Py_RETURN_TRUE;
647 }
648
649 static PyObject *
650 stringio_writable(stringio *self, PyObject *args)
651 {
652 CHECK_INITIALIZED(self);
653 Py_RETURN_TRUE;
654 }
655
656 /* Pickling support.
657
658 The implementation of __getstate__ is similar to the one for BytesIO,
659 except that we also save the newline parameter. For __setstate__ and unlike
660 BytesIO, we call __init__ to restore the object's state. Doing so allows us
661 to avoid decoding the complex newline state while keeping the object
662 representation compact.
663
664 See comment in bytesio.c regarding why only pickle protocols and onward are
665 supported.
666 */
667
668 static PyObject *
669 stringio_getstate(stringio *self)
670 {
671 PyObject *initvalue = stringio_getvalue(self);
672 PyObject *dict;
673 PyObject *state;
674
675 if (initvalue == NULL)
676 return NULL;
677 if (self->dict == NULL) {
678 Py_INCREF(Py_None);
679 dict = Py_None;
680 }
681 else {
682 dict = PyDict_Copy(self->dict);
683 if (dict == NULL)
684 return NULL;
685 }
686
687 state = Py_BuildValue("(OOnN)", initvalue,
688 self->readnl ? self->readnl : Py_None,
689 self->pos, dict);
690 Py_DECREF(initvalue);
691 return state;
692 }
693
694 static PyObject *
695 stringio_setstate(stringio *self, PyObject *state)
696 {
697 PyObject *initarg;
698 PyObject *position_obj;
699 PyObject *dict;
700 Py_ssize_t pos;
701
702 assert(state != NULL);
703 CHECK_CLOSED(self);
704
705 /* We allow the state tuple to be longer than 4, because we may need
706 someday to extend the object's state without breaking
707 backward-compatibility. */
708 if (!PyTuple_Check(state) || Py_SIZE(state) < 4) {
709 PyErr_Format(PyExc_TypeError,
710 "%.200s.__setstate__ argument should be 4-tuple, got %.200s",
711 Py_TYPE(self)->tp_name, Py_TYPE(state)->tp_name);
712 return NULL;
713 }
714
715 /* Initialize the object's state. */
716 initarg = PyTuple_GetSlice(state, 0, 2);
717 if (initarg == NULL)
718 return NULL;
719 if (stringio_init(self, initarg, NULL) < 0) {
720 Py_DECREF(initarg);
721 return NULL;
722 }
723 Py_DECREF(initarg);
724
725 /* Restore the buffer state. Even if __init__ did initialize the buffer,
726 we have to initialize it again since __init__ may translates the
727 newlines in the inital_value string. We clearly do not want that
728 because the string value in the state tuple has already been translated
729 once by __init__. So we do not take any chance and replace object's
730 buffer completely. */
731 {
732 Py_UNICODE *buf = PyUnicode_AS_UNICODE(PyTuple_GET_ITEM(state, 0));
733 Py_ssize_t bufsize = PyUnicode_GET_SIZE(PyTuple_GET_ITEM(state, 0));
734 if (resize_buffer(self, bufsize) < 0)
735 return NULL;
736 memcpy(self->buf, buf, bufsize * sizeof(Py_UNICODE));
737 self->string_size = bufsize;
738 }
739
740 /* Set carefully the position value. Alternatively, we could use the seek
741 method instead of modifying self->pos directly to better protect the
742 object internal state against errneous (or malicious) inputs. */
743 position_obj = PyTuple_GET_ITEM(state, 2);
744 if (!PyIndex_Check(position_obj)) {
745 PyErr_Format(PyExc_TypeError,
746 "third item of state must be an integer, got %.200s",
747 Py_TYPE(position_obj)->tp_name);
748 return NULL;
749 }
750 pos = PyNumber_AsSsize_t(position_obj, PyExc_OverflowError);
751 if (pos == -1 && PyErr_Occurred())
752 return NULL;
753 if (pos < 0) {
754 PyErr_SetString(PyExc_ValueError,
755 "position value cannot be negative");
756 return NULL;
757 }
758 self->pos = pos;
759
760 /* Set the dictionary of the instance variables. */
761 dict = PyTuple_GET_ITEM(state, 3);
762 if (dict != Py_None) {
763 if (!PyDict_Check(dict)) {
764 PyErr_Format(PyExc_TypeError,
765 "fourth item of state should be a dict, got a %.200s",
766 Py_TYPE(dict)->tp_name);
767 return NULL;
768 }
769 if (self->dict) {
770 /* Alternatively, we could replace the internal dictionary
771 completely. However, it seems more practical to just update it. */
772 if (PyDict_Update(self->dict, dict) < 0)
773 return NULL;
774 }
775 else {
776 Py_INCREF(dict);
777 self->dict = dict;
778 }
779 }
780
781 Py_RETURN_NONE;
782 }
783
784
785 static PyObject *
786 stringio_closed(stringio *self, void *context)
787 {
788 CHECK_INITIALIZED(self);
789 return PyBool_FromLong(self->closed);
790 }
791
792 static PyObject *
793 stringio_line_buffering(stringio *self, void *context)
794 {
795 CHECK_INITIALIZED(self);
796 CHECK_CLOSED(self);
797 Py_RETURN_FALSE;
798 }
799
800 static PyObject *
801 stringio_newlines(stringio *self, void *context)
802 {
803 CHECK_INITIALIZED(self);
804 CHECK_CLOSED(self);
805 if (self->decoder == NULL)
806 Py_RETURN_NONE;
807 return PyObject_GetAttr(self->decoder, _PyIO_str_newlines);
808 }
809
810 static struct PyMethodDef stringio_methods[] = {
811 {"close", (PyCFunction)stringio_close, METH_NOARGS, stringio_close_doc},
812 {"getvalue", (PyCFunction)stringio_getvalue, METH_NOARGS, stringio_getvalue_doc},
813 {"read", (PyCFunction)stringio_read, METH_VARARGS, stringio_read_doc},
814 {"readline", (PyCFunction)stringio_readline, METH_VARARGS, stringio_readline_doc},
815 {"tell", (PyCFunction)stringio_tell, METH_NOARGS, stringio_tell_doc},
816 {"truncate", (PyCFunction)stringio_truncate, METH_VARARGS, stringio_truncate_doc},
817 {"seek", (PyCFunction)stringio_seek, METH_VARARGS, stringio_seek_doc},
818 {"write", (PyCFunction)stringio_write, METH_O, stringio_write_doc},
819
820 {"seekable", (PyCFunction)stringio_seekable, METH_NOARGS},
821 {"readable", (PyCFunction)stringio_readable, METH_NOARGS},
822 {"writable", (PyCFunction)stringio_writable, METH_NOARGS},
823
824 {"__getstate__", (PyCFunction)stringio_getstate, METH_NOARGS},
825 {"__setstate__", (PyCFunction)stringio_setstate, METH_O},
826 {NULL, NULL} /* sentinel */
827 };
828
829 static PyGetSetDef stringio_getset[] = {
830 {"closed", (getter)stringio_closed, NULL, NULL},
831 {"newlines", (getter)stringio_newlines, NULL, NULL},
832 /* (following comments straight off of the original Python wrapper:)
833 XXX Cruft to support the TextIOWrapper API. This would only
834 be meaningful if StringIO supported the buffer attribute.
835 Hopefully, a better solution, than adding these pseudo-attributes,
836 will be found.
837 */
838 {"line_buffering", (getter)stringio_line_buffering, NULL, NULL},
839 {NULL}
840 };
841
842 PyTypeObject PyStringIO_Type = {
843 PyVarObject_HEAD_INIT(NULL, 0)
844 "_io.StringIO", /*tp_name*/
845 sizeof(stringio), /*tp_basicsize*/
846 0, /*tp_itemsize*/
847 (destructor)stringio_dealloc, /*tp_dealloc*/
848 0, /*tp_print*/
849 0, /*tp_getattr*/
850 0, /*tp_setattr*/
851 0, /*tp_reserved*/
852 0, /*tp_repr*/
853 0, /*tp_as_number*/
854 0, /*tp_as_sequence*/
855 0, /*tp_as_mapping*/
856 0, /*tp_hash*/
857 0, /*tp_call*/
858 0, /*tp_str*/
859 0, /*tp_getattro*/
860 0, /*tp_setattro*/
861 0, /*tp_as_buffer*/
862 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
863 | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
864 stringio_doc, /*tp_doc*/
865 (traverseproc)stringio_traverse, /*tp_traverse*/
866 (inquiry)stringio_clear, /*tp_clear*/
867 0, /*tp_richcompare*/
868 offsetof(stringio, weakreflist), /*tp_weaklistoffset*/
869 0, /*tp_iter*/
870 (iternextfunc)stringio_iternext, /*tp_iternext*/
871 stringio_methods, /*tp_methods*/
872 0, /*tp_members*/
873 stringio_getset, /*tp_getset*/
874 0, /*tp_base*/
875 0, /*tp_dict*/
876 0, /*tp_descr_get*/
877 0, /*tp_descr_set*/
878 offsetof(stringio, dict), /*tp_dictoffset*/
879 (initproc)stringio_init, /*tp_init*/
880 0, /*tp_alloc*/
881 stringio_new, /*tp_new*/
882 };