blob: 953e8edb519be5b323d6a6a3dca30b19e4211a1e [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
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
Damien68f59a92013-10-20 14:39:58 +010027#include <stdio.h>
28#include <stdarg.h>
29#include <string.h>
Damien George354d15a2014-02-06 21:11:19 +000030#include <assert.h>
Damien George51dfcb42015-01-01 20:27:54 +000031
32#include "py/mpconfig.h"
33#include "py/misc.h"
Damien68f59a92013-10-20 14:39:58 +010034
35// returned value is always at least 1 greater than argument
36#define ROUND_ALLOC(a) (((a) & ((~0) - 7)) + 8)
37
Damien George0d3cb672015-01-28 23:43:01 +000038// Init the vstr so it allocs exactly given number of bytes. Set length to zero.
Damien Georgeb0261342014-09-23 18:10:17 +010039void vstr_init(vstr_t *vstr, size_t alloc) {
Damien George0d3cb672015-01-28 23:43:01 +000040 if (alloc < 1) {
41 alloc = 1;
Damien George8cd72bd2014-03-31 17:10:59 +010042 }
Paul Sokolovsky5d2499c2014-01-13 23:15:23 +020043 vstr->alloc = alloc;
Damien68f59a92013-10-20 14:39:58 +010044 vstr->len = 0;
45 vstr->buf = m_new(char, vstr->alloc);
46 if (vstr->buf == NULL) {
Damien68f59a92013-10-20 14:39:58 +010047 vstr->had_error = true;
48 return;
49 }
Damien68f59a92013-10-20 14:39:58 +010050 vstr->had_error = false;
Damien George354d15a2014-02-06 21:11:19 +000051 vstr->fixed_buf = false;
52}
53
Damien George0d3cb672015-01-28 23:43:01 +000054// Init the vstr so it allocs exactly enough ram to hold given length, and set the length.
Damien George05005f62015-01-21 22:48:37 +000055void vstr_init_len(vstr_t *vstr, size_t len) {
Damien George0d3cb672015-01-28 23:43:01 +000056 vstr_init(vstr, len);
57 vstr->len = len;
Damien George05005f62015-01-21 22:48:37 +000058}
59
Damien Georgeb0261342014-09-23 18:10:17 +010060void vstr_init_fixed_buf(vstr_t *vstr, size_t alloc, char *buf) {
Damien George354d15a2014-02-06 21:11:19 +000061 vstr->alloc = alloc;
62 vstr->len = 0;
63 vstr->buf = buf;
Damien George354d15a2014-02-06 21:11:19 +000064 vstr->had_error = false;
65 vstr->fixed_buf = true;
Damien68f59a92013-10-20 14:39:58 +010066}
67
68void vstr_clear(vstr_t *vstr) {
Damien George354d15a2014-02-06 21:11:19 +000069 if (!vstr->fixed_buf) {
70 m_del(char, vstr->buf, vstr->alloc);
71 }
Damien68f59a92013-10-20 14:39:58 +010072 vstr->buf = NULL;
73}
74
Damien8b3a7c22013-10-23 20:20:17 +010075vstr_t *vstr_new(void) {
Damien George0d3cb672015-01-28 23:43:01 +000076 vstr_t *vstr = m_new_obj(vstr_t);
Damien68f59a92013-10-20 14:39:58 +010077 if (vstr == NULL) {
78 return NULL;
79 }
Damien George0d3cb672015-01-28 23:43:01 +000080 vstr_init(vstr, 16);
Paul Sokolovsky5d2499c2014-01-13 23:15:23 +020081 return vstr;
82}
83
Damien Georgeb0261342014-09-23 18:10:17 +010084vstr_t *vstr_new_size(size_t alloc) {
Damien George0d3cb672015-01-28 23:43:01 +000085 vstr_t *vstr = m_new_obj(vstr_t);
Paul Sokolovsky5d2499c2014-01-13 23:15:23 +020086 if (vstr == NULL) {
87 return NULL;
88 }
89 vstr_init(vstr, alloc);
Damien68f59a92013-10-20 14:39:58 +010090 return vstr;
91}
92
93void vstr_free(vstr_t *vstr) {
94 if (vstr != NULL) {
Damien George354d15a2014-02-06 21:11:19 +000095 if (!vstr->fixed_buf) {
96 m_del(char, vstr->buf, vstr->alloc);
97 }
Damien732407f2013-12-29 19:33:23 +000098 m_del_obj(vstr_t, vstr);
Damien68f59a92013-10-20 14:39:58 +010099 }
100}
101
102void vstr_reset(vstr_t *vstr) {
103 vstr->len = 0;
Damien68f59a92013-10-20 14:39:58 +0100104 vstr->had_error = false;
105}
106
107bool vstr_had_error(vstr_t *vstr) {
108 return vstr->had_error;
109}
110
111char *vstr_str(vstr_t *vstr) {
112 if (vstr->had_error) {
113 return NULL;
114 }
115 return vstr->buf;
116}
117
Damien Georgeb0261342014-09-23 18:10:17 +0100118size_t vstr_len(vstr_t *vstr) {
Damien68f59a92013-10-20 14:39:58 +0100119 if (vstr->had_error) {
120 return 0;
121 }
122 return vstr->len;
123}
124
Damien George0d3cb672015-01-28 23:43:01 +0000125// Extend vstr strictly by requested size, return pointer to newly added chunk.
Damien Georgeb0261342014-09-23 18:10:17 +0100126char *vstr_extend(vstr_t *vstr, size_t size) {
Damien George354d15a2014-02-06 21:11:19 +0000127 if (vstr->fixed_buf) {
128 return NULL;
129 }
Paul Sokolovsky5d2499c2014-01-13 23:15:23 +0200130 char *new_buf = m_renew(char, vstr->buf, vstr->alloc, vstr->alloc + size);
131 if (new_buf == NULL) {
132 vstr->had_error = true;
133 return NULL;
134 }
135 char *p = new_buf + vstr->alloc;
136 vstr->alloc += size;
137 vstr->buf = new_buf;
138 return p;
139}
140
Damien Georgeb0261342014-09-23 18:10:17 +0100141STATIC bool vstr_ensure_extra(vstr_t *vstr, size_t size) {
Damien George0d3cb672015-01-28 23:43:01 +0000142 if (vstr->len + size > vstr->alloc) {
Damien George354d15a2014-02-06 21:11:19 +0000143 if (vstr->fixed_buf) {
144 return false;
145 }
Damien George0d3cb672015-01-28 23:43:01 +0000146 size_t new_alloc = ROUND_ALLOC((vstr->len + size) * 2);
Damien732407f2013-12-29 19:33:23 +0000147 char *new_buf = m_renew(char, vstr->buf, vstr->alloc, new_alloc);
Damien68f59a92013-10-20 14:39:58 +0100148 if (new_buf == NULL) {
149 vstr->had_error = true;
150 return false;
151 }
152 vstr->alloc = new_alloc;
153 vstr->buf = new_buf;
154 }
155 return true;
156}
157
Damien Georgeb0261342014-09-23 18:10:17 +0100158void vstr_hint_size(vstr_t *vstr, size_t size) {
Damien68f59a92013-10-20 14:39:58 +0100159 // it's not an error if we fail to allocate for the size hint
160 bool er = vstr->had_error;
161 vstr_ensure_extra(vstr, size);
162 vstr->had_error = er;
163}
164
Damien Georgeb0261342014-09-23 18:10:17 +0100165char *vstr_add_len(vstr_t *vstr, size_t len) {
Damien68f59a92013-10-20 14:39:58 +0100166 if (vstr->had_error || !vstr_ensure_extra(vstr, len)) {
167 return NULL;
168 }
169 char *buf = vstr->buf + vstr->len;
170 vstr->len += len;
Damien68f59a92013-10-20 14:39:58 +0100171 return buf;
172}
173
Damien George0d3cb672015-01-28 23:43:01 +0000174// Doesn't increase len, just makes sure there is a null byte at the end
Damien George827b0f72015-01-29 13:57:23 +0000175char *vstr_null_terminated_str(vstr_t *vstr) {
Damien George0d3cb672015-01-28 23:43:01 +0000176 if (vstr->had_error || !vstr_ensure_extra(vstr, 1)) {
Damien George827b0f72015-01-29 13:57:23 +0000177 return NULL;
Damien George0d3cb672015-01-28 23:43:01 +0000178 }
179 vstr->buf[vstr->len] = '\0';
Damien George827b0f72015-01-29 13:57:23 +0000180 return vstr->buf;
Damien George0d3cb672015-01-28 23:43:01 +0000181}
182
Damien George280e7202014-03-15 14:33:09 +0000183void vstr_add_byte(vstr_t *vstr, byte b) {
Damien68f59a92013-10-20 14:39:58 +0100184 byte *buf = (byte*)vstr_add_len(vstr, 1);
185 if (buf == NULL) {
186 return;
187 }
Damien George280e7202014-03-15 14:33:09 +0000188 buf[0] = b;
Damien68f59a92013-10-20 14:39:58 +0100189}
190
191void vstr_add_char(vstr_t *vstr, unichar c) {
Paul Sokolovsky165eb692014-06-13 02:42:34 +0300192#if MICROPY_PY_BUILTINS_STR_UNICODE
Chris Angelico2ba22992014-06-04 05:28:12 +1000193 // TODO: Can this be simplified and deduplicated?
194 // Is it worth just calling vstr_add_len(vstr, 4)?
195 if (c < 0x80) {
196 byte *buf = (byte*)vstr_add_len(vstr, 1);
197 if (buf == NULL) {
198 return;
199 }
200 *buf = (byte)c;
201 } else if (c < 0x800) {
202 byte *buf = (byte*)vstr_add_len(vstr, 2);
203 if (buf == NULL) {
204 return;
205 }
206 buf[0] = (c >> 6) | 0xC0;
207 buf[1] = (c & 0x3F) | 0x80;
208 } else if (c < 0x10000) {
209 byte *buf = (byte*)vstr_add_len(vstr, 3);
210 if (buf == NULL) {
211 return;
212 }
213 buf[0] = (c >> 12) | 0xE0;
214 buf[1] = ((c >> 6) & 0x3F) | 0x80;
215 buf[2] = (c & 0x3F) | 0x80;
216 } else {
217 assert(c < 0x110000);
218 byte *buf = (byte*)vstr_add_len(vstr, 4);
219 if (buf == NULL) {
220 return;
221 }
222 buf[0] = (c >> 18) | 0xF0;
223 buf[1] = ((c >> 12) & 0x3F) | 0x80;
224 buf[2] = ((c >> 6) & 0x3F) | 0x80;
225 buf[3] = (c & 0x3F) | 0x80;
Damien68f59a92013-10-20 14:39:58 +0100226 }
Paul Sokolovsky165eb692014-06-13 02:42:34 +0300227#else
Damien George0d3cb672015-01-28 23:43:01 +0000228 vstr_add_byte(vstr, c);
Paul Sokolovsky165eb692014-06-13 02:42:34 +0300229#endif
Damien68f59a92013-10-20 14:39:58 +0100230}
231
232void vstr_add_str(vstr_t *vstr, const char *str) {
233 vstr_add_strn(vstr, str, strlen(str));
234}
235
Damien Georgeb0261342014-09-23 18:10:17 +0100236void vstr_add_strn(vstr_t *vstr, const char *str, size_t len) {
Damien68f59a92013-10-20 14:39:58 +0100237 if (vstr->had_error || !vstr_ensure_extra(vstr, len)) {
Damien George354d15a2014-02-06 21:11:19 +0000238 // if buf is fixed, we got here because there isn't enough room left
Damien George0d3cb672015-01-28 23:43:01 +0000239 // so just try to copy as much as we can, with room for a possible null byte
Damien George354d15a2014-02-06 21:11:19 +0000240 if (vstr->fixed_buf && vstr->len + 1 < vstr->alloc) {
241 len = vstr->alloc - vstr->len - 1;
242 goto copy;
243 }
Damien68f59a92013-10-20 14:39:58 +0100244 return;
245 }
Damien George354d15a2014-02-06 21:11:19 +0000246copy:
Damien68f59a92013-10-20 14:39:58 +0100247 memmove(vstr->buf + vstr->len, str, len);
248 vstr->len += len;
Damien68f59a92013-10-20 14:39:58 +0100249}
250
Damien George969a6b32014-12-10 22:07:04 +0000251STATIC char *vstr_ins_blank_bytes(vstr_t *vstr, size_t byte_pos, size_t byte_len) {
Damien George280e7202014-03-15 14:33:09 +0000252 if (vstr->had_error) {
253 return NULL;
254 }
Damien Georgeb0261342014-09-23 18:10:17 +0100255 size_t l = vstr->len;
Damien George280e7202014-03-15 14:33:09 +0000256 if (byte_pos > l) {
257 byte_pos = l;
258 }
259 if (byte_len > 0) {
260 // ensure room for the new bytes
261 if (!vstr_ensure_extra(vstr, byte_len)) {
262 return NULL;
263 }
Damien George0d3cb672015-01-28 23:43:01 +0000264 // copy up the string to make room for the new bytes
265 memmove(vstr->buf + byte_pos + byte_len, vstr->buf + byte_pos, l - byte_pos);
Damien George280e7202014-03-15 14:33:09 +0000266 // increase the length
267 vstr->len += byte_len;
Damien George280e7202014-03-15 14:33:09 +0000268 }
269 return vstr->buf + byte_pos;
270}
271
Damien Georgeb0261342014-09-23 18:10:17 +0100272void vstr_ins_byte(vstr_t *vstr, size_t byte_pos, byte b) {
Damien George280e7202014-03-15 14:33:09 +0000273 char *s = vstr_ins_blank_bytes(vstr, byte_pos, 1);
274 if (s != NULL) {
275 *s = b;
276 }
277}
278
Damien Georgeb0261342014-09-23 18:10:17 +0100279void vstr_ins_char(vstr_t *vstr, size_t char_pos, unichar chr) {
Damien George280e7202014-03-15 14:33:09 +0000280 // TODO UNICODE
Damien Georgeecd58ae2014-03-15 16:54:06 +0000281 char *s = vstr_ins_blank_bytes(vstr, char_pos, 1);
Damien George280e7202014-03-15 14:33:09 +0000282 if (s != NULL) {
283 *s = chr;
284 }
285}
286
Damien Georgeb0261342014-09-23 18:10:17 +0100287void vstr_cut_head_bytes(vstr_t *vstr, size_t bytes_to_cut) {
Damien George280e7202014-03-15 14:33:09 +0000288 vstr_cut_out_bytes(vstr, 0, bytes_to_cut);
289}
290
Damien Georgeb0261342014-09-23 18:10:17 +0100291void vstr_cut_tail_bytes(vstr_t *vstr, size_t len) {
Damien68f59a92013-10-20 14:39:58 +0100292 if (vstr->had_error) {
293 return;
294 }
295 if (len > vstr->len) {
296 vstr->len = 0;
297 } else {
298 vstr->len -= len;
299 }
300}
301
Damien Georgeb0261342014-09-23 18:10:17 +0100302void vstr_cut_out_bytes(vstr_t *vstr, size_t byte_pos, size_t bytes_to_cut) {
Damien George280e7202014-03-15 14:33:09 +0000303 if (vstr->had_error || byte_pos >= vstr->len) {
304 return;
305 } else if (byte_pos + bytes_to_cut >= vstr->len) {
306 vstr->len = byte_pos;
Damien George280e7202014-03-15 14:33:09 +0000307 } else {
Damien George0d3cb672015-01-28 23:43:01 +0000308 memmove(vstr->buf + byte_pos, vstr->buf + byte_pos + bytes_to_cut, vstr->len - byte_pos - bytes_to_cut);
Damien George280e7202014-03-15 14:33:09 +0000309 vstr->len -= bytes_to_cut;
310 }
311}
312
Damien68f59a92013-10-20 14:39:58 +0100313void vstr_printf(vstr_t *vstr, const char *fmt, ...) {
Damien2f06c572013-11-03 18:20:56 +0000314 va_list ap;
315 va_start(ap, fmt);
316 vstr_vprintf(vstr, fmt, ap);
317 va_end(ap);
318}
319
320void vstr_vprintf(vstr_t *vstr, const char *fmt, va_list ap) {
Damien68f59a92013-10-20 14:39:58 +0100321 if (vstr->had_error || !vstr_ensure_extra(vstr, strlen(fmt))) {
322 return;
323 }
324
325 while (1) {
326 // try to print in the allocated space
Damien George66028ab2014-01-03 14:03:48 +0000327 // need to make a copy of the va_list because we may call vsnprintf multiple times
Damien Georgeb0261342014-09-23 18:10:17 +0100328 size_t size = vstr->alloc - vstr->len;
Damien George66028ab2014-01-03 14:03:48 +0000329 va_list ap2;
330 va_copy(ap2, ap);
331 int n = vsnprintf(vstr->buf + vstr->len, size, fmt, ap2);
332 va_end(ap2);
Damien68f59a92013-10-20 14:39:58 +0100333
334 // if that worked, return
Damien George963a5a32015-01-16 17:47:07 +0000335 if (n > -1 && (size_t)n < size) {
Damien68f59a92013-10-20 14:39:58 +0100336 vstr->len += n;
337 return;
338 }
339
340 // else try again with more space
341 if (n > -1) { // glibc 2.1
342 // n + 1 is precisely what is needed
343 if (!vstr_ensure_extra(vstr, n + 1)) {
344 return;
345 }
346 } else { // glibc 2.0
347 // increase to twice the old size
348 if (!vstr_ensure_extra(vstr, size * 2)) {
349 return;
350 }
351 }
352 }
353}