blob: b602ee83ce0b6de3960510698552c08fa02db5a2 [file] [log] [blame]
Antoine Pitrou19690592009-06-12 20:14:08 +00001#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
10typedef 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
43PyDoc_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. */
53static int
54resize_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. */
108static Py_ssize_t
109write_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 positon
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
180fail:
181 Py_XDECREF(decoded);
182 return -1;
183}
184
185PyDoc_STRVAR(stringio_getvalue_doc,
186 "Retrieve the entire contents of the object.");
187
188static PyObject *
189stringio_getvalue(stringio *self)
190{
191 CHECK_INITIALIZED(self);
192 CHECK_CLOSED(self);
193 return PyUnicode_FromUnicode(self->buf, self->string_size);
194}
195
196PyDoc_STRVAR(stringio_tell_doc,
197 "Tell the current file position.");
198
199static PyObject *
200stringio_tell(stringio *self)
201{
202 CHECK_INITIALIZED(self);
203 CHECK_CLOSED(self);
204 return PyLong_FromSsize_t(self->pos);
205}
206
207PyDoc_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
213static PyObject *
214stringio_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 */
254static 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
283PyDoc_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
288static PyObject *
289stringio_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
312static PyObject *
313stringio_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
349PyDoc_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(). Imply an absolute seek to pos.\n"
354 "Returns the new absolute position.\n");
355
356static PyObject *
357stringio_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 self->pos = size;
394
395 return PyLong_FromSsize_t(size);
396}
397
398PyDoc_STRVAR(stringio_seek_doc,
399 "Change stream position.\n"
400 "\n"
401 "Seek to character offset pos relative to position indicated by whence:\n"
402 " 0 Start of stream (the default). pos should be >= 0;\n"
403 " 1 Current position - pos must be 0;\n"
404 " 2 End of stream - pos must be 0.\n"
405 "Returns the new absolute position.\n");
406
407static PyObject *
408stringio_seek(stringio *self, PyObject *args)
409{
410 PyObject *posobj;
411 Py_ssize_t pos;
412 int mode = 0;
413
414 CHECK_INITIALIZED(self);
415 if (!PyArg_ParseTuple(args, "O|i:seek", &posobj, &mode))
416 return NULL;
417
418 pos = PyNumber_AsSsize_t(posobj, PyExc_OverflowError);
419 if (pos == -1 && PyErr_Occurred())
420 return NULL;
421
422 CHECK_CLOSED(self);
423
424 if (mode != 0 && mode != 1 && mode != 2) {
425 PyErr_Format(PyExc_ValueError,
426 "Invalid whence (%i, should be 0, 1 or 2)", mode);
427 return NULL;
428 }
429 else if (pos < 0 && mode == 0) {
430 PyErr_Format(PyExc_ValueError,
431 "Negative seek position %zd", pos);
432 return NULL;
433 }
434 else if (mode != 0 && pos != 0) {
435 PyErr_SetString(PyExc_IOError,
436 "Can't do nonzero cur-relative seeks");
437 return NULL;
438 }
439
440 /* mode 0: offset relative to beginning of the string.
441 mode 1: no change to current position.
442 mode 2: change position to end of file. */
443 if (mode == 1) {
444 pos = self->pos;
445 }
446 else if (mode == 2) {
447 pos = self->string_size;
448 }
449
450 self->pos = pos;
451
452 return PyLong_FromSsize_t(self->pos);
453}
454
455PyDoc_STRVAR(stringio_write_doc,
456 "Write string to file.\n"
457 "\n"
458 "Returns the number of characters written, which is always equal to\n"
459 "the length of the string.\n");
460
461static PyObject *
462stringio_write(stringio *self, PyObject *obj)
463{
464 Py_ssize_t size;
465
466 CHECK_INITIALIZED(self);
467 if (!PyUnicode_Check(obj)) {
468 PyErr_Format(PyExc_TypeError, "string argument expected, got '%s'",
469 Py_TYPE(obj)->tp_name);
470 return NULL;
471 }
472 CHECK_CLOSED(self);
473 size = PyUnicode_GET_SIZE(obj);
474
475 if (size > 0 && write_str(self, obj) < 0)
476 return NULL;
477
478 return PyLong_FromSsize_t(size);
479}
480
481PyDoc_STRVAR(stringio_close_doc,
482 "Close the IO object. Attempting any further operation after the\n"
483 "object is closed will raise a ValueError.\n"
484 "\n"
485 "This method has no effect if the file is already closed.\n");
486
487static PyObject *
488stringio_close(stringio *self)
489{
490 self->closed = 1;
491 /* Free up some memory */
492 if (resize_buffer(self, 0) < 0)
493 return NULL;
494 Py_CLEAR(self->readnl);
495 Py_CLEAR(self->writenl);
496 Py_CLEAR(self->decoder);
497 Py_RETURN_NONE;
498}
499
500static int
501stringio_traverse(stringio *self, visitproc visit, void *arg)
502{
503 Py_VISIT(self->dict);
504 return 0;
505}
506
507static int
508stringio_clear(stringio *self)
509{
510 Py_CLEAR(self->dict);
511 return 0;
512}
513
514static void
515stringio_dealloc(stringio *self)
516{
517 _PyObject_GC_UNTRACK(self);
518 Py_CLEAR(self->readnl);
519 Py_CLEAR(self->writenl);
520 Py_CLEAR(self->decoder);
521 if (self->buf)
522 PyMem_Free(self->buf);
523 if (self->weakreflist != NULL)
524 PyObject_ClearWeakRefs((PyObject *) self);
525 Py_TYPE(self)->tp_free(self);
526}
527
528static PyObject *
529stringio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
530{
531 stringio *self;
532
533 assert(type != NULL && type->tp_alloc != NULL);
534 self = (stringio *)type->tp_alloc(type, 0);
535 if (self == NULL)
536 return NULL;
537
538 self->string_size = 0;
539 self->pos = 0;
540 self->buf_size = 0;
541 self->buf = (Py_UNICODE *)PyMem_Malloc(0);
542 if (self->buf == NULL) {
543 Py_DECREF(self);
544 return PyErr_NoMemory();
545 }
546
547 return (PyObject *)self;
548}
549
550static int
551stringio_init(stringio *self, PyObject *args, PyObject *kwds)
552{
553 char *kwlist[] = {"initial_value", "newline", NULL};
554 PyObject *value = NULL;
555 char *newline = "\n";
556
557 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oz:__init__", kwlist,
558 &value, &newline))
559 return -1;
560
561 if (newline && newline[0] != '\0'
562 && !(newline[0] == '\n' && newline[1] == '\0')
563 && !(newline[0] == '\r' && newline[1] == '\0')
564 && !(newline[0] == '\r' && newline[1] == '\n' && newline[2] == '\0')) {
565 PyErr_Format(PyExc_ValueError,
566 "illegal newline value: %s", newline);
567 return -1;
568 }
569 if (value && value != Py_None && !PyUnicode_Check(value)) {
570 PyErr_Format(PyExc_ValueError,
571 "initial_value must be str or None, not %.200s",
572 Py_TYPE(value)->tp_name);
573 return -1;
574 }
575
576 self->ok = 0;
577
578 Py_CLEAR(self->readnl);
579 Py_CLEAR(self->writenl);
580 Py_CLEAR(self->decoder);
581
582 if (newline) {
583 self->readnl = PyString_FromString(newline);
584 if (self->readnl == NULL)
585 return -1;
586 }
587 self->readuniversal = (newline == NULL || newline[0] == '\0');
588 self->readtranslate = (newline == NULL);
589 /* If newline == "", we don't translate anything.
590 If newline == "\n" or newline == None, we translate to "\n", which is
591 a no-op.
592 (for newline == None, TextIOWrapper translates to os.sepline, but it
593 is pointless for StringIO)
594 */
595 if (newline != NULL && newline[0] == '\r') {
596 self->writenl = PyUnicode_FromString(newline);
597 }
598
599 if (self->readuniversal) {
600 self->decoder = PyObject_CallFunction(
601 (PyObject *)&PyIncrementalNewlineDecoder_Type,
602 "Oi", Py_None, (int) self->readtranslate);
603 if (self->decoder == NULL)
604 return -1;
605 }
606
607 /* Now everything is set up, resize buffer to size of initial value,
608 and copy it */
609 self->string_size = 0;
610 if (value && value != Py_None) {
611 Py_ssize_t len = PyUnicode_GetSize(value);
612 /* This is a heuristic, for newline translation might change
613 the string length. */
614 if (resize_buffer(self, len) < 0)
615 return -1;
616 self->pos = 0;
617 if (write_str(self, value) < 0)
618 return -1;
619 }
620 else {
621 if (resize_buffer(self, 0) < 0)
622 return -1;
623 }
624 self->pos = 0;
625
626 self->closed = 0;
627 self->ok = 1;
628 return 0;
629}
630
631/* Properties and pseudo-properties */
632static PyObject *
633stringio_seekable(stringio *self, PyObject *args)
634{
635 CHECK_INITIALIZED(self);
636 Py_RETURN_TRUE;
637}
638
639static PyObject *
640stringio_readable(stringio *self, PyObject *args)
641{
642 CHECK_INITIALIZED(self);
643 Py_RETURN_TRUE;
644}
645
646static PyObject *
647stringio_writable(stringio *self, PyObject *args)
648{
649 CHECK_INITIALIZED(self);
650 Py_RETURN_TRUE;
651}
652
653static PyObject *
654stringio_buffer(stringio *self, void *context)
655{
656 PyErr_SetString(_PyIO_unsupported_operation,
657 "buffer attribute is unsupported on type StringIO");
658 return NULL;
659}
660
661static PyObject *
662stringio_closed(stringio *self, void *context)
663{
664 CHECK_INITIALIZED(self);
665 return PyBool_FromLong(self->closed);
666}
667
668static PyObject *
669stringio_line_buffering(stringio *self, void *context)
670{
671 CHECK_INITIALIZED(self);
672 CHECK_CLOSED(self);
673 Py_RETURN_FALSE;
674}
675
676static PyObject *
677stringio_newlines(stringio *self, void *context)
678{
679 CHECK_INITIALIZED(self);
680 CHECK_CLOSED(self);
681 if (self->decoder == NULL)
682 Py_RETURN_NONE;
683 return PyObject_GetAttr(self->decoder, _PyIO_str_newlines);
684}
685
686static struct PyMethodDef stringio_methods[] = {
687 {"close", (PyCFunction)stringio_close, METH_NOARGS, stringio_close_doc},
688 {"getvalue", (PyCFunction)stringio_getvalue, METH_VARARGS, stringio_getvalue_doc},
689 {"read", (PyCFunction)stringio_read, METH_VARARGS, stringio_read_doc},
690 {"readline", (PyCFunction)stringio_readline, METH_VARARGS, stringio_readline_doc},
691 {"tell", (PyCFunction)stringio_tell, METH_NOARGS, stringio_tell_doc},
692 {"truncate", (PyCFunction)stringio_truncate, METH_VARARGS, stringio_truncate_doc},
693 {"seek", (PyCFunction)stringio_seek, METH_VARARGS, stringio_seek_doc},
694 {"write", (PyCFunction)stringio_write, METH_O, stringio_write_doc},
695
696 {"seekable", (PyCFunction)stringio_seekable, METH_NOARGS},
697 {"readable", (PyCFunction)stringio_readable, METH_NOARGS},
698 {"writable", (PyCFunction)stringio_writable, METH_NOARGS},
699 {NULL, NULL} /* sentinel */
700};
701
702static PyGetSetDef stringio_getset[] = {
703 {"closed", (getter)stringio_closed, NULL, NULL},
704 {"newlines", (getter)stringio_newlines, NULL, NULL},
705 /* (following comments straight off of the original Python wrapper:)
706 XXX Cruft to support the TextIOWrapper API. This would only
707 be meaningful if StringIO supported the buffer attribute.
708 Hopefully, a better solution, than adding these pseudo-attributes,
709 will be found.
710 */
711 {"buffer", (getter)stringio_buffer, NULL, NULL},
712 {"line_buffering", (getter)stringio_line_buffering, NULL, NULL},
713 {NULL}
714};
715
716PyTypeObject PyStringIO_Type = {
717 PyVarObject_HEAD_INIT(NULL, 0)
718 "_io.StringIO", /*tp_name*/
719 sizeof(stringio), /*tp_basicsize*/
720 0, /*tp_itemsize*/
721 (destructor)stringio_dealloc, /*tp_dealloc*/
722 0, /*tp_print*/
723 0, /*tp_getattr*/
724 0, /*tp_setattr*/
725 0, /*tp_reserved*/
726 0, /*tp_repr*/
727 0, /*tp_as_number*/
728 0, /*tp_as_sequence*/
729 0, /*tp_as_mapping*/
730 0, /*tp_hash*/
731 0, /*tp_call*/
732 0, /*tp_str*/
733 0, /*tp_getattro*/
734 0, /*tp_setattro*/
735 0, /*tp_as_buffer*/
736 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
737 | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
738 stringio_doc, /*tp_doc*/
739 (traverseproc)stringio_traverse, /*tp_traverse*/
740 (inquiry)stringio_clear, /*tp_clear*/
741 0, /*tp_richcompare*/
742 offsetof(stringio, weakreflist), /*tp_weaklistoffset*/
743 0, /*tp_iter*/
744 (iternextfunc)stringio_iternext, /*tp_iternext*/
745 stringio_methods, /*tp_methods*/
746 0, /*tp_members*/
747 stringio_getset, /*tp_getset*/
748 0, /*tp_base*/
749 0, /*tp_dict*/
750 0, /*tp_descr_get*/
751 0, /*tp_descr_set*/
752 offsetof(stringio, dict), /*tp_dictoffset*/
753 (initproc)stringio_init, /*tp_init*/
754 0, /*tp_alloc*/
755 stringio_new, /*tp_new*/
756};