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 |
|
---|
636 | PyDoc_STRVAR(stringio_readable_doc,
|
---|
637 | "readable() -> bool. Returns True if the IO object can be read.");
|
---|
638 |
|
---|
639 | PyDoc_STRVAR(stringio_writable_doc,
|
---|
640 | "writable() -> bool. Returns True if the IO object can be written.");
|
---|
641 |
|
---|
642 | PyDoc_STRVAR(stringio_seekable_doc,
|
---|
643 | "seekable() -> bool. Returns True if the IO object can be seeked.");
|
---|
644 |
|
---|
645 | static PyObject *
|
---|
646 | stringio_seekable(stringio *self, PyObject *args)
|
---|
647 | {
|
---|
648 | CHECK_INITIALIZED(self);
|
---|
649 | CHECK_CLOSED(self);
|
---|
650 | Py_RETURN_TRUE;
|
---|
651 | }
|
---|
652 |
|
---|
653 | static PyObject *
|
---|
654 | stringio_readable(stringio *self, PyObject *args)
|
---|
655 | {
|
---|
656 | CHECK_INITIALIZED(self);
|
---|
657 | CHECK_CLOSED(self);
|
---|
658 | Py_RETURN_TRUE;
|
---|
659 | }
|
---|
660 |
|
---|
661 | static PyObject *
|
---|
662 | stringio_writable(stringio *self, PyObject *args)
|
---|
663 | {
|
---|
664 | CHECK_INITIALIZED(self);
|
---|
665 | CHECK_CLOSED(self);
|
---|
666 | Py_RETURN_TRUE;
|
---|
667 | }
|
---|
668 |
|
---|
669 | /* Pickling support.
|
---|
670 |
|
---|
671 | The implementation of __getstate__ is similar to the one for BytesIO,
|
---|
672 | except that we also save the newline parameter. For __setstate__ and unlike
|
---|
673 | BytesIO, we call __init__ to restore the object's state. Doing so allows us
|
---|
674 | to avoid decoding the complex newline state while keeping the object
|
---|
675 | representation compact.
|
---|
676 |
|
---|
677 | See comment in bytesio.c regarding why only pickle protocols and onward are
|
---|
678 | supported.
|
---|
679 | */
|
---|
680 |
|
---|
681 | static PyObject *
|
---|
682 | stringio_getstate(stringio *self)
|
---|
683 | {
|
---|
684 | PyObject *initvalue = stringio_getvalue(self);
|
---|
685 | PyObject *dict;
|
---|
686 | PyObject *state;
|
---|
687 |
|
---|
688 | if (initvalue == NULL)
|
---|
689 | return NULL;
|
---|
690 | if (self->dict == NULL) {
|
---|
691 | Py_INCREF(Py_None);
|
---|
692 | dict = Py_None;
|
---|
693 | }
|
---|
694 | else {
|
---|
695 | dict = PyDict_Copy(self->dict);
|
---|
696 | if (dict == NULL)
|
---|
697 | return NULL;
|
---|
698 | }
|
---|
699 |
|
---|
700 | state = Py_BuildValue("(OOnN)", initvalue,
|
---|
701 | self->readnl ? self->readnl : Py_None,
|
---|
702 | self->pos, dict);
|
---|
703 | Py_DECREF(initvalue);
|
---|
704 | return state;
|
---|
705 | }
|
---|
706 |
|
---|
707 | static PyObject *
|
---|
708 | stringio_setstate(stringio *self, PyObject *state)
|
---|
709 | {
|
---|
710 | PyObject *initarg;
|
---|
711 | PyObject *position_obj;
|
---|
712 | PyObject *dict;
|
---|
713 | Py_ssize_t pos;
|
---|
714 |
|
---|
715 | assert(state != NULL);
|
---|
716 | CHECK_CLOSED(self);
|
---|
717 |
|
---|
718 | /* We allow the state tuple to be longer than 4, because we may need
|
---|
719 | someday to extend the object's state without breaking
|
---|
720 | backward-compatibility. */
|
---|
721 | if (!PyTuple_Check(state) || Py_SIZE(state) < 4) {
|
---|
722 | PyErr_Format(PyExc_TypeError,
|
---|
723 | "%.200s.__setstate__ argument should be 4-tuple, got %.200s",
|
---|
724 | Py_TYPE(self)->tp_name, Py_TYPE(state)->tp_name);
|
---|
725 | return NULL;
|
---|
726 | }
|
---|
727 |
|
---|
728 | /* Initialize the object's state. */
|
---|
729 | initarg = PyTuple_GetSlice(state, 0, 2);
|
---|
730 | if (initarg == NULL)
|
---|
731 | return NULL;
|
---|
732 | if (stringio_init(self, initarg, NULL) < 0) {
|
---|
733 | Py_DECREF(initarg);
|
---|
734 | return NULL;
|
---|
735 | }
|
---|
736 | Py_DECREF(initarg);
|
---|
737 |
|
---|
738 | /* Restore the buffer state. Even if __init__ did initialize the buffer,
|
---|
739 | we have to initialize it again since __init__ may translates the
|
---|
740 | newlines in the inital_value string. We clearly do not want that
|
---|
741 | because the string value in the state tuple has already been translated
|
---|
742 | once by __init__. So we do not take any chance and replace object's
|
---|
743 | buffer completely. */
|
---|
744 | {
|
---|
745 | Py_UNICODE *buf = PyUnicode_AS_UNICODE(PyTuple_GET_ITEM(state, 0));
|
---|
746 | Py_ssize_t bufsize = PyUnicode_GET_SIZE(PyTuple_GET_ITEM(state, 0));
|
---|
747 | if (resize_buffer(self, bufsize) < 0)
|
---|
748 | return NULL;
|
---|
749 | memcpy(self->buf, buf, bufsize * sizeof(Py_UNICODE));
|
---|
750 | self->string_size = bufsize;
|
---|
751 | }
|
---|
752 |
|
---|
753 | /* Set carefully the position value. Alternatively, we could use the seek
|
---|
754 | method instead of modifying self->pos directly to better protect the
|
---|
755 | object internal state against errneous (or malicious) inputs. */
|
---|
756 | position_obj = PyTuple_GET_ITEM(state, 2);
|
---|
757 | if (!PyIndex_Check(position_obj)) {
|
---|
758 | PyErr_Format(PyExc_TypeError,
|
---|
759 | "third item of state must be an integer, got %.200s",
|
---|
760 | Py_TYPE(position_obj)->tp_name);
|
---|
761 | return NULL;
|
---|
762 | }
|
---|
763 | pos = PyNumber_AsSsize_t(position_obj, PyExc_OverflowError);
|
---|
764 | if (pos == -1 && PyErr_Occurred())
|
---|
765 | return NULL;
|
---|
766 | if (pos < 0) {
|
---|
767 | PyErr_SetString(PyExc_ValueError,
|
---|
768 | "position value cannot be negative");
|
---|
769 | return NULL;
|
---|
770 | }
|
---|
771 | self->pos = pos;
|
---|
772 |
|
---|
773 | /* Set the dictionary of the instance variables. */
|
---|
774 | dict = PyTuple_GET_ITEM(state, 3);
|
---|
775 | if (dict != Py_None) {
|
---|
776 | if (!PyDict_Check(dict)) {
|
---|
777 | PyErr_Format(PyExc_TypeError,
|
---|
778 | "fourth item of state should be a dict, got a %.200s",
|
---|
779 | Py_TYPE(dict)->tp_name);
|
---|
780 | return NULL;
|
---|
781 | }
|
---|
782 | if (self->dict) {
|
---|
783 | /* Alternatively, we could replace the internal dictionary
|
---|
784 | completely. However, it seems more practical to just update it. */
|
---|
785 | if (PyDict_Update(self->dict, dict) < 0)
|
---|
786 | return NULL;
|
---|
787 | }
|
---|
788 | else {
|
---|
789 | Py_INCREF(dict);
|
---|
790 | self->dict = dict;
|
---|
791 | }
|
---|
792 | }
|
---|
793 |
|
---|
794 | Py_RETURN_NONE;
|
---|
795 | }
|
---|
796 |
|
---|
797 |
|
---|
798 | static PyObject *
|
---|
799 | stringio_closed(stringio *self, void *context)
|
---|
800 | {
|
---|
801 | CHECK_INITIALIZED(self);
|
---|
802 | return PyBool_FromLong(self->closed);
|
---|
803 | }
|
---|
804 |
|
---|
805 | static PyObject *
|
---|
806 | stringio_line_buffering(stringio *self, void *context)
|
---|
807 | {
|
---|
808 | CHECK_INITIALIZED(self);
|
---|
809 | CHECK_CLOSED(self);
|
---|
810 | Py_RETURN_FALSE;
|
---|
811 | }
|
---|
812 |
|
---|
813 | static PyObject *
|
---|
814 | stringio_newlines(stringio *self, void *context)
|
---|
815 | {
|
---|
816 | CHECK_INITIALIZED(self);
|
---|
817 | CHECK_CLOSED(self);
|
---|
818 | if (self->decoder == NULL)
|
---|
819 | Py_RETURN_NONE;
|
---|
820 | return PyObject_GetAttr(self->decoder, _PyIO_str_newlines);
|
---|
821 | }
|
---|
822 |
|
---|
823 | static struct PyMethodDef stringio_methods[] = {
|
---|
824 | {"close", (PyCFunction)stringio_close, METH_NOARGS, stringio_close_doc},
|
---|
825 | {"getvalue", (PyCFunction)stringio_getvalue, METH_NOARGS, stringio_getvalue_doc},
|
---|
826 | {"read", (PyCFunction)stringio_read, METH_VARARGS, stringio_read_doc},
|
---|
827 | {"readline", (PyCFunction)stringio_readline, METH_VARARGS, stringio_readline_doc},
|
---|
828 | {"tell", (PyCFunction)stringio_tell, METH_NOARGS, stringio_tell_doc},
|
---|
829 | {"truncate", (PyCFunction)stringio_truncate, METH_VARARGS, stringio_truncate_doc},
|
---|
830 | {"seek", (PyCFunction)stringio_seek, METH_VARARGS, stringio_seek_doc},
|
---|
831 | {"write", (PyCFunction)stringio_write, METH_O, stringio_write_doc},
|
---|
832 |
|
---|
833 | {"seekable", (PyCFunction)stringio_seekable, METH_NOARGS, stringio_seekable_doc},
|
---|
834 | {"readable", (PyCFunction)stringio_readable, METH_NOARGS, stringio_readable_doc},
|
---|
835 | {"writable", (PyCFunction)stringio_writable, METH_NOARGS, stringio_writable_doc},
|
---|
836 |
|
---|
837 | {"__getstate__", (PyCFunction)stringio_getstate, METH_NOARGS},
|
---|
838 | {"__setstate__", (PyCFunction)stringio_setstate, METH_O},
|
---|
839 | {NULL, NULL} /* sentinel */
|
---|
840 | };
|
---|
841 |
|
---|
842 | static PyGetSetDef stringio_getset[] = {
|
---|
843 | {"closed", (getter)stringio_closed, NULL, NULL},
|
---|
844 | {"newlines", (getter)stringio_newlines, NULL, NULL},
|
---|
845 | /* (following comments straight off of the original Python wrapper:)
|
---|
846 | XXX Cruft to support the TextIOWrapper API. This would only
|
---|
847 | be meaningful if StringIO supported the buffer attribute.
|
---|
848 | Hopefully, a better solution, than adding these pseudo-attributes,
|
---|
849 | will be found.
|
---|
850 | */
|
---|
851 | {"line_buffering", (getter)stringio_line_buffering, NULL, NULL},
|
---|
852 | {NULL}
|
---|
853 | };
|
---|
854 |
|
---|
855 | PyTypeObject PyStringIO_Type = {
|
---|
856 | PyVarObject_HEAD_INIT(NULL, 0)
|
---|
857 | "_io.StringIO", /*tp_name*/
|
---|
858 | sizeof(stringio), /*tp_basicsize*/
|
---|
859 | 0, /*tp_itemsize*/
|
---|
860 | (destructor)stringio_dealloc, /*tp_dealloc*/
|
---|
861 | 0, /*tp_print*/
|
---|
862 | 0, /*tp_getattr*/
|
---|
863 | 0, /*tp_setattr*/
|
---|
864 | 0, /*tp_reserved*/
|
---|
865 | 0, /*tp_repr*/
|
---|
866 | 0, /*tp_as_number*/
|
---|
867 | 0, /*tp_as_sequence*/
|
---|
868 | 0, /*tp_as_mapping*/
|
---|
869 | 0, /*tp_hash*/
|
---|
870 | 0, /*tp_call*/
|
---|
871 | 0, /*tp_str*/
|
---|
872 | 0, /*tp_getattro*/
|
---|
873 | 0, /*tp_setattro*/
|
---|
874 | 0, /*tp_as_buffer*/
|
---|
875 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
|
---|
876 | | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
|
---|
877 | stringio_doc, /*tp_doc*/
|
---|
878 | (traverseproc)stringio_traverse, /*tp_traverse*/
|
---|
879 | (inquiry)stringio_clear, /*tp_clear*/
|
---|
880 | 0, /*tp_richcompare*/
|
---|
881 | offsetof(stringio, weakreflist), /*tp_weaklistoffset*/
|
---|
882 | 0, /*tp_iter*/
|
---|
883 | (iternextfunc)stringio_iternext, /*tp_iternext*/
|
---|
884 | stringio_methods, /*tp_methods*/
|
---|
885 | 0, /*tp_members*/
|
---|
886 | stringio_getset, /*tp_getset*/
|
---|
887 | 0, /*tp_base*/
|
---|
888 | 0, /*tp_dict*/
|
---|
889 | 0, /*tp_descr_get*/
|
---|
890 | 0, /*tp_descr_set*/
|
---|
891 | offsetof(stringio, dict), /*tp_dictoffset*/
|
---|
892 | (initproc)stringio_init, /*tp_init*/
|
---|
893 | 0, /*tp_alloc*/
|
---|
894 | stringio_new, /*tp_new*/
|
---|
895 | };
|
---|