blob: a430fca3b7a6c894ef1408fdf5506e45c859eef9 [file] [log] [blame]
Damien George04b91472014-05-03 23:27:38 +01001/*
2 * This file is part of the Micro Python project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2013, 2014 Damien P. George
Paul Sokolovskya47b64a2014-05-15 07:28:19 +03007 * Copyright (c) 2014 Paul Sokolovsky
Damien George04b91472014-05-03 23:27:38 +01008 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030028#include <stdio.h>
29#include <string.h>
30
Damien George51dfcb42015-01-01 20:27:54 +000031#include "py/nlr.h"
32#include "py/objstr.h"
Damien Georgee93c1ca2016-10-13 11:43:28 +110033#include "py/objstringio.h"
Damien George51dfcb42015-01-01 20:27:54 +000034#include "py/runtime.h"
35#include "py/stream.h"
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030036
Damien Georgeee3fd462014-05-24 23:03:12 +010037#if MICROPY_PY_IO
Paul Sokolovsky100cd362014-04-26 20:59:39 +030038
stijnbf195412015-01-16 13:36:18 +010039#if MICROPY_CPYTHON_COMPAT
40STATIC void check_stringio_is_open(const mp_obj_stringio_t *o) {
41 if (o->vstr == NULL) {
Damien George7d0d7212016-10-17 12:17:37 +110042 mp_raise_msg(&mp_type_ValueError, "I/O operation on closed file");
stijnbf195412015-01-16 13:36:18 +010043 }
44}
45#else
46#define check_stringio_is_open(o)
47#endif
48
Damien George7f9d1d62015-04-09 23:56:15 +010049STATIC void stringio_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
Damien Georgeff8dd3f2015-01-20 12:47:20 +000050 (void)kind;
Damien George999cedb2015-11-27 17:01:44 +000051 mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in);
Damien George7f9d1d62015-04-09 23:56:15 +010052 mp_printf(print, self->base.type == &mp_type_stringio ? "<io.StringIO 0x%x>" : "<io.BytesIO 0x%x>", self);
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030053}
54
Damien Georgeadf0f2a2014-07-27 22:38:58 +010055STATIC mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
Damien Georgeff8dd3f2015-01-20 12:47:20 +000056 (void)errcode;
Damien George999cedb2015-11-27 17:01:44 +000057 mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in);
stijnbf195412015-01-16 13:36:18 +010058 check_stringio_is_open(o);
Damien George40f3c022014-07-03 13:25:24 +010059 mp_uint_t remaining = o->vstr->len - o->pos;
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030060 if (size > remaining) {
61 size = remaining;
62 }
63 memcpy(buf, o->vstr->buf + o->pos, size);
64 o->pos += size;
65 return size;
66}
67
Damien Georgeadf0f2a2014-07-27 22:38:58 +010068STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
Damien Georgeff8dd3f2015-01-20 12:47:20 +000069 (void)errcode;
Damien George999cedb2015-11-27 17:01:44 +000070 mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in);
stijnbf195412015-01-16 13:36:18 +010071 check_stringio_is_open(o);
Paul Sokolovsky3990b172016-07-28 01:53:44 +030072 mp_int_t remaining = o->vstr->alloc - o->pos;
73 mp_uint_t org_len = o->vstr->len;
74 if ((mp_int_t)size > remaining) {
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030075 // Take all what's already allocated...
76 o->vstr->len = o->vstr->alloc;
77 // ... and add more
78 vstr_add_len(o->vstr, size - remaining);
79 }
Paul Sokolovsky3990b172016-07-28 01:53:44 +030080 // If there was a seek past EOF, clear the hole
81 if (o->pos > org_len) {
82 memset(o->vstr->buf + org_len, 0, o->pos - org_len);
83 }
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030084 memcpy(o->vstr->buf + o->pos, buf, size);
85 o->pos += size;
86 if (o->pos > o->vstr->len) {
87 o->vstr->len = o->pos;
88 }
89 return size;
90}
91
Paul Sokolovskyf039ac52016-07-28 01:14:32 +030092STATIC mp_uint_t stringio_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
93 (void)errcode;
Paul Sokolovsky3990b172016-07-28 01:53:44 +030094 mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in);
Paul Sokolovskyf039ac52016-07-28 01:14:32 +030095 switch (request) {
Paul Sokolovsky3990b172016-07-28 01:53:44 +030096 case MP_STREAM_SEEK: {
97 struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)arg;
98 mp_uint_t ref = 0;
99 switch (s->whence) {
100 case 1: // SEEK_CUR
101 ref = o->pos;
102 break;
103 case 2: // SEEK_END
104 ref = o->vstr->len;
105 break;
106 }
107 o->pos = ref + s->offset;
108 s->offset = o->pos;
109 return 0;
110 }
Paul Sokolovskyf039ac52016-07-28 01:14:32 +0300111 case MP_STREAM_FLUSH:
112 return 0;
113 default:
114 *errcode = MP_EINVAL;
115 return MP_STREAM_ERROR;
116 }
117}
118
Paul Sokolovskya47b64a2014-05-15 07:28:19 +0300119#define STREAM_TO_CONTENT_TYPE(o) (((o)->base.type == &mp_type_stringio) ? &mp_type_str : &mp_type_bytes)
120
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300121STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) {
Damien George999cedb2015-11-27 17:01:44 +0000122 mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in);
stijnbf195412015-01-16 13:36:18 +0100123 check_stringio_is_open(self);
Paul Sokolovsky2ae66972016-05-13 01:35:52 +0300124 // TODO: Try to avoid copying string
Damien Georgef600a6a2014-05-25 22:34:34 +0100125 return mp_obj_new_str_of_type(STREAM_TO_CONTENT_TYPE(self), (byte*)self->vstr->buf, self->vstr->len);
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300126}
127STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue);
128
129STATIC mp_obj_t stringio_close(mp_obj_t self_in) {
Damien George999cedb2015-11-27 17:01:44 +0000130 mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in);
stijnbf195412015-01-16 13:36:18 +0100131#if MICROPY_CPYTHON_COMPAT
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300132 vstr_free(self->vstr);
133 self->vstr = NULL;
stijnbf195412015-01-16 13:36:18 +0100134#else
135 vstr_clear(self->vstr);
136 self->vstr->alloc = 0;
137 self->vstr->len = 0;
138 self->pos = 0;
139#endif
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300140 return mp_const_none;
141}
142STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_close_obj, stringio_close);
143
Damien George4b72b3a2016-01-03 14:21:40 +0000144STATIC mp_obj_t stringio___exit__(size_t n_args, const mp_obj_t *args) {
Damien Georgeff8dd3f2015-01-20 12:47:20 +0000145 (void)n_args;
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300146 return stringio_close(args[0]);
147}
148STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stringio___exit___obj, 4, 4, stringio___exit__);
149
Damien George5b3f0b72016-01-03 15:55:55 +0000150STATIC mp_obj_stringio_t *stringio_new(const mp_obj_type_t *type) {
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300151 mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t);
Damien George5b3f0b72016-01-03 15:55:55 +0000152 o->base.type = type;
Damien George824f5c52016-10-14 16:46:34 +1100153 o->vstr = vstr_new(16);
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300154 o->pos = 0;
155 return o;
156}
157
Damien George5b3f0b72016-01-03 15:55:55 +0000158STATIC mp_obj_t stringio_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
Damien Georgeff8dd3f2015-01-20 12:47:20 +0000159 (void)n_kw; // TODO check n_kw==0
Paul Sokolovskya47b64a2014-05-15 07:28:19 +0300160 mp_obj_stringio_t *o = stringio_new(type_in);
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300161
162 if (n_args > 0) {
163 mp_buffer_info_t bufinfo;
164 mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
Damien George999cedb2015-11-27 17:01:44 +0000165 stringio_write(MP_OBJ_FROM_PTR(o), bufinfo.buf, bufinfo.len, NULL);
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300166 // Cur ptr is always at the beginning of buffer at the construction
167 o->pos = 0;
168 }
Damien George999cedb2015-11-27 17:01:44 +0000169 return MP_OBJ_FROM_PTR(o);
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300170}
171
Damien Georgecbf76742015-11-27 13:38:15 +0000172STATIC const mp_rom_map_elem_t stringio_locals_dict_table[] = {
173 { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
Paul Sokolovskyd22a04d2016-10-09 11:56:11 +0300174 { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
Damien Georgecbf76742015-11-27 13:38:15 +0000175 { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
176 { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
Paul Sokolovsky3990b172016-07-28 01:53:44 +0300177 { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },
Paul Sokolovskyf039ac52016-07-28 01:14:32 +0300178 { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },
Damien Georgecbf76742015-11-27 13:38:15 +0000179 { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&stringio_close_obj) },
180 { MP_ROM_QSTR(MP_QSTR_getvalue), MP_ROM_PTR(&stringio_getvalue_obj) },
181 { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
182 { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&stringio___exit___obj) },
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300183};
184
185STATIC MP_DEFINE_CONST_DICT(stringio_locals_dict, stringio_locals_dict_table);
186
187STATIC const mp_stream_p_t stringio_stream_p = {
188 .read = stringio_read,
189 .write = stringio_write,
Paul Sokolovskyf039ac52016-07-28 01:14:32 +0300190 .ioctl = stringio_ioctl,
Damien Georgeadf0f2a2014-07-27 22:38:58 +0100191 .is_text = true,
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300192};
193
Paul Sokolovskya47b64a2014-05-15 07:28:19 +0300194STATIC const mp_stream_p_t bytesio_stream_p = {
195 .read = stringio_read,
196 .write = stringio_write,
Paul Sokolovskyf039ac52016-07-28 01:14:32 +0300197 .ioctl = stringio_ioctl,
Paul Sokolovskya47b64a2014-05-15 07:28:19 +0300198};
199
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300200const mp_obj_type_t mp_type_stringio = {
201 { &mp_type_type },
202 .name = MP_QSTR_StringIO,
203 .print = stringio_print,
204 .make_new = stringio_make_new,
205 .getiter = mp_identity,
206 .iternext = mp_stream_unbuffered_iter,
Paul Sokolovsky07209f82016-06-18 18:19:24 +0300207 .protocol = &stringio_stream_p,
Damien George999cedb2015-11-27 17:01:44 +0000208 .locals_dict = (mp_obj_dict_t*)&stringio_locals_dict,
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300209};
Paul Sokolovsky100cd362014-04-26 20:59:39 +0300210
Damien Georgeee3fd462014-05-24 23:03:12 +0100211#if MICROPY_PY_IO_BYTESIO
Paul Sokolovskya47b64a2014-05-15 07:28:19 +0300212const mp_obj_type_t mp_type_bytesio = {
213 { &mp_type_type },
214 .name = MP_QSTR_BytesIO,
215 .print = stringio_print,
216 .make_new = stringio_make_new,
217 .getiter = mp_identity,
218 .iternext = mp_stream_unbuffered_iter,
Paul Sokolovsky07209f82016-06-18 18:19:24 +0300219 .protocol = &bytesio_stream_p,
Damien George999cedb2015-11-27 17:01:44 +0000220 .locals_dict = (mp_obj_dict_t*)&stringio_locals_dict,
Paul Sokolovskya47b64a2014-05-15 07:28:19 +0300221};
222#endif
223
Paul Sokolovsky100cd362014-04-26 20:59:39 +0300224#endif