Branch data Line data Source code
1 : : /*
2 : : * This file is part of the MicroPython project, http://micropython.org/
3 : : *
4 : : * The MIT License (MIT)
5 : : *
6 : : * Copyright (c) 2013, 2014 Damien P. George
7 : : * Copyright (c) 2014-2016 Paul Sokolovsky
8 : : *
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 : :
28 : : #include <string.h>
29 : : #include <assert.h>
30 : :
31 : : #include "py/objstr.h"
32 : : #include "py/objlist.h"
33 : : #include "py/runtime.h"
34 : :
35 : : #if MICROPY_PY_BUILTINS_STR_UNICODE
36 : :
37 : : static mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf);
38 : :
39 : : /******************************************************************************/
40 : : /* str */
41 : :
42 : 3766 : static void uni_print_quoted(const mp_print_t *print, const byte *str_data, uint str_len) {
43 : : // this escapes characters, but it will be very slow to print (calling print many times)
44 : 3766 : bool has_single_quote = false;
45 : 3766 : bool has_double_quote = false;
46 [ + + ]: 26362 : for (const byte *s = str_data, *top = str_data + str_len; !has_double_quote && s < top; s++) {
47 [ + + ]: 22596 : if (*s == '\'') {
48 : : has_single_quote = true;
49 [ + + ]: 22358 : } else if (*s == '"') {
50 : 14 : has_double_quote = true;
51 : : }
52 : : }
53 : 3766 : unichar quote_char = '\'';
54 [ + + ]: 3766 : if (has_single_quote && !has_double_quote) {
55 : 86 : quote_char = '"';
56 : : }
57 : 3766 : mp_printf(print, "%c", quote_char);
58 : 3766 : const byte *s = str_data, *top = str_data + str_len;
59 [ + + ]: 26354 : while (s < top) {
60 : 22588 : unichar ch;
61 : 22588 : ch = utf8_get_char(s);
62 : 22588 : s = utf8_next_char(s);
63 [ + + ]: 22588 : if (ch == quote_char) {
64 : 4 : mp_printf(print, "\\%c", quote_char);
65 [ + + ]: 22584 : } else if (ch == '\\') {
66 : 4 : mp_print_str(print, "\\\\");
67 [ + + ]: 22580 : } else if (32 <= ch && ch <= 126) {
68 : 22308 : mp_printf(print, "%c", ch);
69 [ + + ]: 272 : } else if (ch == '\n') {
70 : 78 : mp_print_str(print, "\\n");
71 [ + + ]: 194 : } else if (ch == '\r') {
72 : 40 : mp_print_str(print, "\\r");
73 [ + + ]: 154 : } else if (ch == '\t') {
74 : 8 : mp_print_str(print, "\\t");
75 [ + + ]: 146 : } else if (ch < 0x100) {
76 : 142 : mp_printf(print, "\\x%02x", ch);
77 [ + + ]: 4 : } else if (ch < 0x10000) {
78 : 2 : mp_printf(print, "\\u%04x", ch);
79 : : } else {
80 : 2 : mp_printf(print, "\\U%08x", ch);
81 : : }
82 : : }
83 : 3766 : mp_printf(print, "%c", quote_char);
84 : 3766 : }
85 : :
86 : 177398 : static void uni_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
87 [ + + ]: 177398 : GET_STR_DATA_LEN(self_in, str_data, str_len);
88 : : #if MICROPY_PY_JSON
89 [ + + ]: 177398 : if (kind == PRINT_JSON) {
90 : 114 : mp_str_print_json(print, str_data, str_len);
91 : 114 : return;
92 : : }
93 : : #endif
94 [ + + ]: 177284 : if (kind == PRINT_STR) {
95 : 173518 : print->print_strn(print->data, (const char *)str_data, str_len);
96 : : } else {
97 : 3766 : uni_print_quoted(print, str_data, str_len);
98 : : }
99 : : }
100 : :
101 : 16456 : static mp_obj_t uni_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
102 [ + + ]: 16456 : GET_STR_DATA_LEN(self_in, str_data, str_len);
103 [ + + + ]: 16456 : switch (op) {
104 : 10156 : case MP_UNARY_OP_BOOL:
105 [ + + ]: 10156 : return mp_obj_new_bool(str_len != 0);
106 : 5650 : case MP_UNARY_OP_LEN:
107 : 5650 : return MP_OBJ_NEW_SMALL_INT(utf8_charlen(str_data, str_len));
108 : : default:
109 : : return MP_OBJ_NULL; // op not supported
110 : : }
111 : : }
112 : :
113 : : // Convert an index into a pointer to its lead byte. Out of bounds indexing will raise IndexError or
114 : : // be capped to the first/last character of the string, depending on is_slice.
115 : 2462 : const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, size_t self_len,
116 : : mp_obj_t index, bool is_slice) {
117 : : // All str functions also handle bytes objects, and they call str_index_to_ptr(),
118 : : // so it must handle bytes.
119 [ + + ]: 2462 : if (type == &mp_type_bytes
120 : : #if MICROPY_PY_BUILTINS_BYTEARRAY
121 [ + + ]: 2254 : || type == &mp_type_bytearray
122 : : #endif
123 : : ) {
124 : : // Taken from objstr.c:str_index_to_ptr()
125 : 212 : size_t index_val = mp_get_index(type, self_len, index, is_slice);
126 : 212 : return self_data + index_val;
127 : : }
128 : :
129 : 2250 : mp_int_t i;
130 : : // Copied from mp_get_index; I don't want bounds checking, just give me
131 : : // the integer as-is. (I can't bounds-check without scanning the whole
132 : : // string; an out-of-bounds index will be caught in the loops below.)
133 [ + + ]: 2250 : if (mp_obj_is_small_int(index)) {
134 : 2226 : i = MP_OBJ_SMALL_INT_VALUE(index);
135 [ + + ]: 24 : } else if (!mp_obj_get_int_maybe(index, &i)) {
136 : 4 : mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("string indices must be integers, not %s"), mp_obj_get_type_str(index));
137 : : }
138 : 2246 : const byte *s, *top = self_data + self_len;
139 [ + + ]: 2246 : if (i < 0) {
140 : : // Negative indexing is performed by counting from the end of the string.
141 [ + + ]: 7090 : for (s = top - 1; i; --s) {
142 [ + + ]: 6496 : if (s < self_data) {
143 [ + + ]: 48 : if (is_slice) {
144 : : return self_data;
145 : : }
146 : 6 : mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("string index out of range"));
147 : : }
148 [ + + ]: 6448 : if (!UTF8_IS_CONT(*s)) {
149 : 2642 : ++i;
150 : : }
151 : : }
152 : 594 : ++s;
153 : : } else {
154 : : // Positive indexing, correspondingly, counts from the start of the string.
155 : : // It's assumed that negative indexing will generally be used with small
156 : : // absolute values (eg str[-1], not str[-1000000]), which means it'll be
157 : : // more efficient this way.
158 : : s = self_data;
159 : 6668 : while (1) {
160 : : // First check out-of-bounds
161 [ + + ]: 6668 : if (s >= top) {
162 [ + + ]: 134 : if (is_slice) {
163 : : return top;
164 : : }
165 : 6 : mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("string index out of range"));
166 : : }
167 : : // Then check completion
168 [ + + ]: 6534 : if (i-- == 0) {
169 : : break;
170 : : }
171 : : // Then skip UTF-8 char
172 : 5064 : ++s;
173 [ + + ]: 6528 : while (UTF8_IS_CONT(*s)) {
174 : 1464 : ++s;
175 : : }
176 : : }
177 : : }
178 : : return s;
179 : : }
180 : :
181 : 1208 : static mp_obj_t str_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
182 : 1208 : const mp_obj_type_t *type = mp_obj_get_type(self_in);
183 [ - + ]: 1208 : assert(type == &mp_type_str);
184 [ + + ]: 1208 : GET_STR_DATA_LEN(self_in, self_data, self_len);
185 [ + + ]: 1208 : if (value == MP_OBJ_SENTINEL) {
186 : : // load
187 : : #if MICROPY_PY_BUILTINS_SLICE
188 [ - + - + : 1204 : if (mp_obj_is_type(index, &mp_type_slice)) {
- + + + +
- ]
189 : 902 : mp_obj_t ostart, ostop, ostep;
190 : 902 : mp_obj_slice_t *slice = MP_OBJ_TO_PTR(index);
191 : 902 : ostart = slice->start;
192 : 902 : ostop = slice->stop;
193 : 902 : ostep = slice->step;
194 : :
195 [ + + ]: 902 : if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) {
196 : 2 : mp_raise_NotImplementedError(MP_ERROR_TEXT("only slices with step=1 (aka None) are supported"));
197 : : }
198 : :
199 : 900 : const byte *pstart, *pstop;
200 [ + + ]: 900 : if (ostart != mp_const_none) {
201 : 660 : pstart = str_index_to_ptr(type, self_data, self_len, ostart, true);
202 : : } else {
203 : : pstart = self_data;
204 : : }
205 [ + + ]: 900 : if (ostop != mp_const_none) {
206 : : // pstop will point just after the stop character. This depends on
207 : : // the \0 at the end of the string.
208 : 724 : pstop = str_index_to_ptr(type, self_data, self_len, ostop, true);
209 : : } else {
210 : 176 : pstop = self_data + self_len;
211 : : }
212 [ + + ]: 900 : if (pstop < pstart) {
213 : : return MP_OBJ_NEW_QSTR(MP_QSTR_);
214 : : }
215 : 812 : return mp_obj_new_str_of_type(type, (const byte *)pstart, pstop - pstart);
216 : : }
217 : : #endif
218 : 302 : const byte *s = str_index_to_ptr(type, self_data, self_len, index, false);
219 : 286 : int len = 1;
220 [ + + ]: 286 : if (UTF8_IS_NONASCII(*s)) {
221 : : // Count the number of 1 bits (after the first)
222 [ + + ]: 168 : for (char mask = 0x40; *s & mask; mask >>= 1) {
223 : 100 : ++len;
224 : : }
225 : : }
226 : 286 : return mp_obj_new_str_via_qstr((const char *)s, len); // This will create a one-character string
227 : : } else {
228 : : return MP_OBJ_NULL; // op not supported
229 : : }
230 : : }
231 : :
232 : : MP_DEFINE_CONST_OBJ_TYPE(
233 : : mp_type_str,
234 : : MP_QSTR_str,
235 : : MP_TYPE_FLAG_ITER_IS_GETITER,
236 : : make_new, mp_obj_str_make_new,
237 : : print, uni_print,
238 : : unary_op, uni_unary_op,
239 : : binary_op, mp_obj_str_binary_op,
240 : : subscr, str_subscr,
241 : : iter, mp_obj_new_str_iterator,
242 : : buffer, mp_obj_str_get_buffer,
243 : : locals_dict, &mp_obj_str_locals_dict
244 : : );
245 : :
246 : : /******************************************************************************/
247 : : /* str iterator */
248 : :
249 : : typedef struct _mp_obj_str_it_t {
250 : : mp_obj_base_t base;
251 : : mp_fun_1_t iternext;
252 : : mp_obj_t str;
253 : : size_t cur;
254 : : } mp_obj_str_it_t;
255 : :
256 : 674 : static mp_obj_t str_it_iternext(mp_obj_t self_in) {
257 : 674 : mp_obj_str_it_t *self = MP_OBJ_TO_PTR(self_in);
258 [ + + ]: 674 : GET_STR_DATA_LEN(self->str, str, len);
259 [ + + ]: 674 : if (self->cur < len) {
260 : 498 : const byte *cur = str + self->cur;
261 : 498 : const byte *end = utf8_next_char(str + self->cur);
262 : 498 : mp_obj_t o_out = mp_obj_new_str_via_qstr((const char *)cur, end - cur);
263 : 498 : self->cur += end - cur;
264 : 498 : return o_out;
265 : : } else {
266 : : return MP_OBJ_STOP_ITERATION;
267 : : }
268 : : }
269 : :
270 : 180 : static mp_obj_t mp_obj_new_str_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf) {
271 : 180 : assert(sizeof(mp_obj_str_it_t) <= sizeof(mp_obj_iter_buf_t));
272 : 180 : mp_obj_str_it_t *o = (mp_obj_str_it_t *)iter_buf;
273 : 180 : o->base.type = &mp_type_polymorph_iter;
274 : 180 : o->iternext = str_it_iternext;
275 : 180 : o->str = str;
276 : 180 : o->cur = 0;
277 : 180 : return MP_OBJ_FROM_PTR(o);
278 : : }
279 : :
280 : : #endif // MICROPY_PY_BUILTINS_STR_UNICODE
|