blob: 5fd2ca9d3b2195f0960873c9f2627ba27a6a2552 [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"
33#include "py/runtime.h"
34#include "py/stream.h"
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030035
Damien Georgeee3fd462014-05-24 23:03:12 +010036#if MICROPY_PY_IO
Paul Sokolovsky100cd362014-04-26 20:59:39 +030037
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030038typedef struct _mp_obj_stringio_t {
39 mp_obj_base_t base;
40 vstr_t *vstr;
41 // StringIO has single pointer used for both reading and writing
Damien George40f3c022014-07-03 13:25:24 +010042 mp_uint_t pos;
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030043} mp_obj_stringio_t;
44
stijnbf195412015-01-16 13:36:18 +010045#if MICROPY_CPYTHON_COMPAT
46STATIC void check_stringio_is_open(const mp_obj_stringio_t *o) {
47 if (o->vstr == NULL) {
48 nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "I/O operation on closed file"));
49 }
50}
51#else
52#define check_stringio_is_open(o)
53#endif
54
Damien George7f9d1d62015-04-09 23:56:15 +010055STATIC 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 +000056 (void)kind;
Damien George999cedb2015-11-27 17:01:44 +000057 mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in);
Damien George7f9d1d62015-04-09 23:56:15 +010058 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 +030059}
60
Damien Georgeadf0f2a2014-07-27 22:38:58 +010061STATIC 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 +000062 (void)errcode;
Damien George999cedb2015-11-27 17:01:44 +000063 mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in);
stijnbf195412015-01-16 13:36:18 +010064 check_stringio_is_open(o);
Damien George40f3c022014-07-03 13:25:24 +010065 mp_uint_t remaining = o->vstr->len - o->pos;
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030066 if (size > remaining) {
67 size = remaining;
68 }
69 memcpy(buf, o->vstr->buf + o->pos, size);
70 o->pos += size;
71 return size;
72}
73
Damien Georgeadf0f2a2014-07-27 22:38:58 +010074STATIC 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 +000075 (void)errcode;
Damien George999cedb2015-11-27 17:01:44 +000076 mp_obj_stringio_t *o = MP_OBJ_TO_PTR(o_in);
stijnbf195412015-01-16 13:36:18 +010077 check_stringio_is_open(o);
Damien George40f3c022014-07-03 13:25:24 +010078 mp_uint_t remaining = o->vstr->alloc - o->pos;
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030079 if (size > remaining) {
80 // Take all what's already allocated...
81 o->vstr->len = o->vstr->alloc;
82 // ... and add more
83 vstr_add_len(o->vstr, size - remaining);
84 }
85 memcpy(o->vstr->buf + o->pos, buf, size);
86 o->pos += size;
87 if (o->pos > o->vstr->len) {
88 o->vstr->len = o->pos;
89 }
90 return size;
91}
92
Paul Sokolovskya47b64a2014-05-15 07:28:19 +030093#define STREAM_TO_CONTENT_TYPE(o) (((o)->base.type == &mp_type_stringio) ? &mp_type_str : &mp_type_bytes)
94
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030095STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) {
Damien George999cedb2015-11-27 17:01:44 +000096 mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in);
stijnbf195412015-01-16 13:36:18 +010097 check_stringio_is_open(self);
Paul Sokolovsky2ae66972016-05-13 01:35:52 +030098 // TODO: Try to avoid copying string
Damien Georgef600a6a2014-05-25 22:34:34 +010099 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 +0300100}
101STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue);
102
103STATIC mp_obj_t stringio_close(mp_obj_t self_in) {
Damien George999cedb2015-11-27 17:01:44 +0000104 mp_obj_stringio_t *self = MP_OBJ_TO_PTR(self_in);
stijnbf195412015-01-16 13:36:18 +0100105#if MICROPY_CPYTHON_COMPAT
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300106 vstr_free(self->vstr);
107 self->vstr = NULL;
stijnbf195412015-01-16 13:36:18 +0100108#else
109 vstr_clear(self->vstr);
110 self->vstr->alloc = 0;
111 self->vstr->len = 0;
112 self->pos = 0;
113#endif
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300114 return mp_const_none;
115}
116STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_close_obj, stringio_close);
117
Damien George4b72b3a2016-01-03 14:21:40 +0000118STATIC mp_obj_t stringio___exit__(size_t n_args, const mp_obj_t *args) {
Damien Georgeff8dd3f2015-01-20 12:47:20 +0000119 (void)n_args;
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300120 return stringio_close(args[0]);
121}
122STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stringio___exit___obj, 4, 4, stringio___exit__);
123
Damien George5b3f0b72016-01-03 15:55:55 +0000124STATIC mp_obj_stringio_t *stringio_new(const mp_obj_type_t *type) {
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300125 mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t);
Damien George5b3f0b72016-01-03 15:55:55 +0000126 o->base.type = type;
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300127 o->vstr = vstr_new();
128 o->pos = 0;
129 return o;
130}
131
Damien George5b3f0b72016-01-03 15:55:55 +0000132STATIC 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 +0000133 (void)n_kw; // TODO check n_kw==0
Paul Sokolovskya47b64a2014-05-15 07:28:19 +0300134 mp_obj_stringio_t *o = stringio_new(type_in);
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300135
136 if (n_args > 0) {
137 mp_buffer_info_t bufinfo;
138 mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
Damien George999cedb2015-11-27 17:01:44 +0000139 stringio_write(MP_OBJ_FROM_PTR(o), bufinfo.buf, bufinfo.len, NULL);
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300140 // Cur ptr is always at the beginning of buffer at the construction
141 o->pos = 0;
142 }
Damien George999cedb2015-11-27 17:01:44 +0000143 return MP_OBJ_FROM_PTR(o);
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300144}
145
Damien Georgecbf76742015-11-27 13:38:15 +0000146STATIC const mp_rom_map_elem_t stringio_locals_dict_table[] = {
147 { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
148 { MP_ROM_QSTR(MP_QSTR_readall), MP_ROM_PTR(&mp_stream_readall_obj) },
149 { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
150 { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
151 { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&stringio_close_obj) },
152 { MP_ROM_QSTR(MP_QSTR_getvalue), MP_ROM_PTR(&stringio_getvalue_obj) },
153 { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
154 { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&stringio___exit___obj) },
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300155};
156
157STATIC MP_DEFINE_CONST_DICT(stringio_locals_dict, stringio_locals_dict_table);
158
159STATIC const mp_stream_p_t stringio_stream_p = {
160 .read = stringio_read,
161 .write = stringio_write,
Damien Georgeadf0f2a2014-07-27 22:38:58 +0100162 .is_text = true,
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300163};
164
Paul Sokolovskya47b64a2014-05-15 07:28:19 +0300165STATIC const mp_stream_p_t bytesio_stream_p = {
166 .read = stringio_read,
167 .write = stringio_write,
Paul Sokolovskya47b64a2014-05-15 07:28:19 +0300168};
169
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300170const mp_obj_type_t mp_type_stringio = {
171 { &mp_type_type },
172 .name = MP_QSTR_StringIO,
173 .print = stringio_print,
174 .make_new = stringio_make_new,
175 .getiter = mp_identity,
176 .iternext = mp_stream_unbuffered_iter,
177 .stream_p = &stringio_stream_p,
Damien George999cedb2015-11-27 17:01:44 +0000178 .locals_dict = (mp_obj_dict_t*)&stringio_locals_dict,
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300179};
Paul Sokolovsky100cd362014-04-26 20:59:39 +0300180
Damien Georgeee3fd462014-05-24 23:03:12 +0100181#if MICROPY_PY_IO_BYTESIO
Paul Sokolovskya47b64a2014-05-15 07:28:19 +0300182const mp_obj_type_t mp_type_bytesio = {
183 { &mp_type_type },
184 .name = MP_QSTR_BytesIO,
185 .print = stringio_print,
186 .make_new = stringio_make_new,
187 .getiter = mp_identity,
188 .iternext = mp_stream_unbuffered_iter,
189 .stream_p = &bytesio_stream_p,
Damien George999cedb2015-11-27 17:01:44 +0000190 .locals_dict = (mp_obj_dict_t*)&stringio_locals_dict,
Paul Sokolovskya47b64a2014-05-15 07:28:19 +0300191};
192#endif
193
Paul Sokolovsky100cd362014-04-26 20:59:39 +0300194#endif