blob: eca8522eefca51159cc8be1b53e812a3e7224116 [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
45STATIC void stringio_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
46 mp_obj_stringio_t *self = self_in;
Paul Sokolovskya47b64a2014-05-15 07:28:19 +030047 print(env, self->base.type == &mp_type_stringio ? "<io.StringIO 0x%x>" : "<io.BytesIO 0x%x>", self->vstr);
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030048}
49
Damien Georgeadf0f2a2014-07-27 22:38:58 +010050STATIC mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030051 mp_obj_stringio_t *o = o_in;
Damien George40f3c022014-07-03 13:25:24 +010052 mp_uint_t remaining = o->vstr->len - o->pos;
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030053 if (size > remaining) {
54 size = remaining;
55 }
56 memcpy(buf, o->vstr->buf + o->pos, size);
57 o->pos += size;
58 return size;
59}
60
Damien Georgeadf0f2a2014-07-27 22:38:58 +010061STATIC mp_uint_t stringio_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030062 mp_obj_stringio_t *o = o_in;
Damien George40f3c022014-07-03 13:25:24 +010063 mp_uint_t remaining = o->vstr->alloc - o->pos;
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030064 if (size > remaining) {
65 // Take all what's already allocated...
66 o->vstr->len = o->vstr->alloc;
67 // ... and add more
68 vstr_add_len(o->vstr, size - remaining);
69 }
70 memcpy(o->vstr->buf + o->pos, buf, size);
71 o->pos += size;
72 if (o->pos > o->vstr->len) {
73 o->vstr->len = o->pos;
74 }
75 return size;
76}
77
Paul Sokolovskya47b64a2014-05-15 07:28:19 +030078#define STREAM_TO_CONTENT_TYPE(o) (((o)->base.type == &mp_type_stringio) ? &mp_type_str : &mp_type_bytes)
79
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030080STATIC mp_obj_t stringio_getvalue(mp_obj_t self_in) {
81 mp_obj_stringio_t *self = self_in;
Damien Georgef600a6a2014-05-25 22:34:34 +010082 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 +030083}
84STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_getvalue_obj, stringio_getvalue);
85
86STATIC mp_obj_t stringio_close(mp_obj_t self_in) {
87 mp_obj_stringio_t *self = self_in;
88 vstr_free(self->vstr);
89 self->vstr = NULL;
90 return mp_const_none;
91}
92STATIC MP_DEFINE_CONST_FUN_OBJ_1(stringio_close_obj, stringio_close);
93
Damien George969a6b32014-12-10 22:07:04 +000094STATIC mp_obj_t stringio___exit__(mp_uint_t n_args, const mp_obj_t *args) {
Paul Sokolovskycb9dc082014-04-26 20:26:14 +030095 return stringio_close(args[0]);
96}
97STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stringio___exit___obj, 4, 4, stringio___exit__);
98
Paul Sokolovskya47b64a2014-05-15 07:28:19 +030099STATIC mp_obj_stringio_t *stringio_new(mp_obj_t type_in) {
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300100 mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t);
Paul Sokolovskya47b64a2014-05-15 07:28:19 +0300101 o->base.type = type_in;
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300102 o->vstr = vstr_new();
103 o->pos = 0;
104 return o;
105}
106
Damien Georgeecc88e92014-08-30 00:35:11 +0100107STATIC mp_obj_t stringio_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
Paul Sokolovskya47b64a2014-05-15 07:28:19 +0300108 mp_obj_stringio_t *o = stringio_new(type_in);
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300109
110 if (n_args > 0) {
111 mp_buffer_info_t bufinfo;
112 mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ);
113 stringio_write(o, bufinfo.buf, bufinfo.len, NULL);
114 // Cur ptr is always at the beginning of buffer at the construction
115 o->pos = 0;
116 }
117 return o;
118}
119
120STATIC const mp_map_elem_t stringio_locals_dict_table[] = {
121 { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
122 { MP_OBJ_NEW_QSTR(MP_QSTR_readall), (mp_obj_t)&mp_stream_readall_obj },
123 { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj},
124 { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj },
125 { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&stringio_close_obj },
126 { MP_OBJ_NEW_QSTR(MP_QSTR_getvalue), (mp_obj_t)&stringio_getvalue_obj },
127 { MP_OBJ_NEW_QSTR(MP_QSTR___enter__), (mp_obj_t)&mp_identity_obj },
128 { MP_OBJ_NEW_QSTR(MP_QSTR___exit__), (mp_obj_t)&stringio___exit___obj },
129};
130
131STATIC MP_DEFINE_CONST_DICT(stringio_locals_dict, stringio_locals_dict_table);
132
133STATIC const mp_stream_p_t stringio_stream_p = {
134 .read = stringio_read,
135 .write = stringio_write,
Damien Georgeadf0f2a2014-07-27 22:38:58 +0100136 .is_text = true,
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300137};
138
Paul Sokolovskya47b64a2014-05-15 07:28:19 +0300139STATIC const mp_stream_p_t bytesio_stream_p = {
140 .read = stringio_read,
141 .write = stringio_write,
Paul Sokolovskya47b64a2014-05-15 07:28:19 +0300142};
143
Paul Sokolovskycb9dc082014-04-26 20:26:14 +0300144const mp_obj_type_t mp_type_stringio = {
145 { &mp_type_type },
146 .name = MP_QSTR_StringIO,
147 .print = stringio_print,
148 .make_new = stringio_make_new,
149 .getiter = mp_identity,
150 .iternext = mp_stream_unbuffered_iter,
151 .stream_p = &stringio_stream_p,
152 .locals_dict = (mp_obj_t)&stringio_locals_dict,
153};
Paul Sokolovsky100cd362014-04-26 20:59:39 +0300154
Damien Georgeee3fd462014-05-24 23:03:12 +0100155#if MICROPY_PY_IO_BYTESIO
Paul Sokolovskya47b64a2014-05-15 07:28:19 +0300156const mp_obj_type_t mp_type_bytesio = {
157 { &mp_type_type },
158 .name = MP_QSTR_BytesIO,
159 .print = stringio_print,
160 .make_new = stringio_make_new,
161 .getiter = mp_identity,
162 .iternext = mp_stream_unbuffered_iter,
163 .stream_p = &bytesio_stream_p,
164 .locals_dict = (mp_obj_t)&stringio_locals_dict,
165};
166#endif
167
Paul Sokolovsky100cd362014-04-26 20:59:39 +0300168#endif