Commit 7f9d1d6a authored by Damien George's avatar Damien George
Browse files

py: Overhaul and simplify printf/pfenv mechanism.

Previous to this patch the printing mechanism was a bit of a tangled
mess.  This patch attempts to consolidate printing into one interface.

All (non-debug) printing now uses the mp_print* family of functions,
mainly mp_printf.  All these functions take an mp_print_t structure as
their first argument, and this structure defines the printing backend
through the "print_strn" function of said structure.

Printing from the uPy core can reach the platform-defined print code via
two paths: either through mp_sys_stdout_obj (defined pert port) in
conjunction with mp_stream_write; or through the mp_plat_print structure
which uses the MP_PLAT_PRINT_STRN macro to define how string are printed
on the platform.  The former is only used when MICROPY_PY_IO is defined.

With this new scheme printing is generally more efficient (less layers
to go through, less arguments to pass), and, given an mp_print_t*
structure, one can call mp_print_str for efficiency instead of
mp_printf("%s", ...).  Code size is also reduced by around 200 bytes on
Thumb2 archs.
parent 56beb017
......@@ -50,7 +50,7 @@ typedef enum {
mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val);
#endif // MICROPY_PY_BUILTINS_FLOAT
void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind);
void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind);
char *mp_obj_int_formatted(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_size, mp_const_obj_t self_in,
int base, const char *prefix, char base_char, char comma);
char *mp_obj_int_formatted_impl(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_size, mp_const_obj_t self_in,
......
......@@ -44,19 +44,19 @@ STATIC mp_obj_t list_pop(mp_uint_t n_args, const mp_obj_t *args);
/******************************************************************************/
/* list */
STATIC void list_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
STATIC void list_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
mp_obj_list_t *o = MP_OBJ_CAST(o_in);
if (!(MICROPY_PY_UJSON && kind == PRINT_JSON)) {
kind = PRINT_REPR;
}
print(env, "[");
mp_print_str(print, "[");
for (mp_uint_t i = 0; i < o->len; i++) {
if (i > 0) {
print(env, ", ");
mp_print_str(print, ", ");
}
mp_obj_print_helper(print, env, o->items[i], kind);
mp_obj_print_helper(print, o->items[i], kind);
}
print(env, "]");
mp_print_str(print, "]");
}
STATIC mp_obj_t list_extend_from_iter(mp_obj_t list, mp_obj_t iterable) {
......
......@@ -33,7 +33,7 @@
#include "py/runtime.h"
#include "py/builtin.h"
STATIC void module_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_module_t *self = self_in;
const char *name = qstr_str(self->name);
......@@ -43,12 +43,12 @@ STATIC void module_print(void (*print)(void *env, const char *fmt, ...), void *e
// symbol to give more information about the module.
mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___file__), MP_MAP_LOOKUP);
if (elem != NULL) {
print(env, "<module '%s' from '%s'>", name, mp_obj_str_get_str(elem->value));
mp_printf(print, "<module '%s' from '%s'>", name, mp_obj_str_get_str(elem->value));
return;
}
#endif
print(env, "<module '%s'>", name);
mp_printf(print, "<module '%s'>", name);
}
STATIC void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
......
......@@ -53,19 +53,19 @@ STATIC mp_uint_t namedtuple_find_field(mp_obj_namedtuple_type_t *type, qstr name
return -1;
}
STATIC void namedtuple_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
STATIC void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_namedtuple_t *o = o_in;
print(env, "%s(", qstr_str(o->tuple.base.type->name));
mp_printf(print, "%s(", qstr_str(o->tuple.base.type->name));
const qstr *fields = ((mp_obj_namedtuple_type_t*)o->tuple.base.type)->fields;
for (mp_uint_t i = 0; i < o->tuple.len; i++) {
if (i > 0) {
print(env, ", ");
mp_print_str(print, ", ");
}
print(env, "%s=", qstr_str(fields[i]));
mp_obj_print_helper(print, env, o->tuple.items[i], PRINT_REPR);
mp_printf(print, "%s=", qstr_str(fields[i]));
mp_obj_print_helper(print, o->tuple.items[i], PRINT_REPR);
}
print(env, ")");
mp_print_str(print, ")");
}
STATIC void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
......
......@@ -34,12 +34,12 @@ typedef struct _mp_obj_none_t {
mp_obj_base_t base;
} mp_obj_none_t;
STATIC void none_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void none_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)self_in;
if (MICROPY_PY_UJSON && kind == PRINT_JSON) {
print(env, "null");
mp_print_str(print, "null");
} else {
print(env, "None");
mp_print_str(print, "None");
}
}
......
......@@ -79,14 +79,14 @@ typedef struct _mp_obj_range_t {
mp_int_t step;
} mp_obj_range_t;
STATIC void range_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void range_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_range_t *self = self_in;
print(env, "range(%d, %d", self->start, self->stop);
mp_printf(print, "range(%d, %d", self->start, self->stop);
if (self->step == 1) {
print(env, ")");
mp_print_str(print, ")");
} else {
print(env, ", %d)", self->step);
mp_printf(print, ", %d)", self->step);
}
}
......
......@@ -79,7 +79,7 @@ STATIC void check_set(mp_obj_t o) {
}
}
STATIC void set_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void set_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_set_t *self = self_in;
#if MICROPY_PY_BUILTINS_FROZENSET
......@@ -88,37 +88,36 @@ STATIC void set_print(void (*print)(void *env, const char *fmt, ...), void *env,
if (self->set.used == 0) {
#if MICROPY_PY_BUILTINS_FROZENSET
if (is_frozen) {
print(env, "frozen");
mp_print_str(print, "frozen");
}
#endif
print(env, "set()");
mp_print_str(print, "set()");
return;
}
bool first = true;
#if MICROPY_PY_BUILTINS_FROZENSET
if (is_frozen) {
print(env, "frozenset(");
mp_print_str(print, "frozenset(");
}
#endif
print(env, "{");
mp_print_str(print, "{");
for (mp_uint_t i = 0; i < self->set.alloc; i++) {
if (MP_SET_SLOT_IS_FILLED(&self->set, i)) {
if (!first) {
print(env, ", ");
mp_print_str(print, ", ");
}
first = false;
mp_obj_print_helper(print, env, self->set.table[i], PRINT_REPR);
mp_obj_print_helper(print, self->set.table[i], PRINT_REPR);
}
}
print(env, "}");
mp_print_str(print, "}");
#if MICROPY_PY_BUILTINS_FROZENSET
if (is_frozen) {
print(env, ")");
mp_print_str(print, ")");
}
#endif
}
STATIC mp_obj_t set_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
......
......@@ -38,10 +38,10 @@ typedef struct _mp_obj_ellipsis_t {
mp_obj_base_t base;
} mp_obj_ellipsis_t;
STATIC void ellipsis_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void ellipsis_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)self_in;
(void)kind;
print(env, "Ellipsis");
mp_print_str(print, "Ellipsis");
}
const mp_obj_type_t mp_type_ellipsis = {
......@@ -66,16 +66,16 @@ typedef struct _mp_obj_slice_t {
mp_obj_t step;
} mp_obj_slice_t;
STATIC void slice_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
STATIC void slice_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_slice_t *o = o_in;
print(env, "slice(");
mp_obj_print_helper(print, env, o->start, PRINT_REPR);
print(env, ", ");
mp_obj_print_helper(print, env, o->stop, PRINT_REPR);
print(env, ", ");
mp_obj_print_helper(print, env, o->step, PRINT_REPR);
print(env, ")");
mp_print_str(print, "slice(");
mp_obj_print_helper(print, o->start, PRINT_REPR);
mp_print_str(print, ", ");
mp_obj_print_helper(print, o->stop, PRINT_REPR);
mp_print_str(print, ", ");
mp_obj_print_helper(print, o->step, PRINT_REPR);
mp_print_str(print, ")");
}
const mp_obj_type_t mp_type_slice = {
......
......@@ -34,7 +34,6 @@
#include "py/objlist.h"
#include "py/runtime0.h"
#include "py/runtime.h"
#include "py/pfenv.h"
STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, mp_uint_t n_args, const mp_obj_t *args, mp_obj_t dict);
......@@ -45,8 +44,7 @@ STATIC NORETURN void bad_implicit_conversion(mp_obj_t self_in);
/******************************************************************************/
/* str */
void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env,
const byte *str_data, mp_uint_t str_len, bool is_bytes) {
void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, mp_uint_t str_len, bool is_bytes) {
// this escapes characters, but it will be very slow to print (calling print many times)
bool has_single_quote = false;
bool has_double_quote = false;
......@@ -61,72 +59,72 @@ void mp_str_print_quoted(void (*print)(void *env, const char *fmt, ...), void *e
if (has_single_quote && !has_double_quote) {
quote_char = '"';
}
print(env, "%c", quote_char);
mp_printf(print, "%c", quote_char);
for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) {
if (*s == quote_char) {
print(env, "\\%c", quote_char);
mp_printf(print, "\\%c", quote_char);
} else if (*s == '\\') {
print(env, "\\\\");
mp_print_str(print, "\\\\");
} else if (*s >= 0x20 && *s != 0x7f && (!is_bytes || *s < 0x80)) {
// In strings, anything which is not ascii control character
// is printed as is, this includes characters in range 0x80-0xff
// (which can be non-Latin letters, etc.)
print(env, "%c", *s);
mp_printf(print, "%c", *s);
} else if (*s == '\n') {
print(env, "\\n");
mp_print_str(print, "\\n");
} else if (*s == '\r') {
print(env, "\\r");
mp_print_str(print, "\\r");
} else if (*s == '\t') {
print(env, "\\t");
mp_print_str(print, "\\t");
} else {
print(env, "\\x%02x", *s);
mp_printf(print, "\\x%02x", *s);
}
}
print(env, "%c", quote_char);
mp_printf(print, "%c", quote_char);
}
#if MICROPY_PY_UJSON
void mp_str_print_json(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, mp_uint_t str_len) {
void mp_str_print_json(const mp_print_t *print, const byte *str_data, mp_uint_t str_len) {
// for JSON spec, see http://www.ietf.org/rfc/rfc4627.txt
// if we are given a valid utf8-encoded string, we will print it in a JSON-conforming way
print(env, "\"");
mp_print_str(print, "\"");
for (const byte *s = str_data, *top = str_data + str_len; s < top; s++) {
if (*s == '"' || *s == '\\') {
print(env, "\\%c", *s);
mp_printf(print, "\\%c", *s);
} else if (*s >= 32) {
// this will handle normal and utf-8 encoded chars
print(env, "%c", *s);
mp_printf(print, "%c", *s);
} else if (*s == '\n') {
print(env, "\\n");
mp_print_str(print, "\\n");
} else if (*s == '\r') {
print(env, "\\r");
mp_print_str(print, "\\r");
} else if (*s == '\t') {
print(env, "\\t");
mp_print_str(print, "\\t");
} else {
// this will handle control chars
print(env, "\\u%04x", *s);
mp_printf(print, "\\u%04x", *s);
}
}
print(env, "\"");
mp_print_str(print, "\"");
}
#endif
STATIC void str_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void str_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
GET_STR_DATA_LEN(self_in, str_data, str_len);
#if MICROPY_PY_UJSON
if (kind == PRINT_JSON) {
mp_str_print_json(print, env, str_data, str_len);
mp_str_print_json(print, str_data, str_len);
return;
}
#endif
bool is_bytes = MP_OBJ_IS_TYPE(self_in, &mp_type_bytes);
if (kind == PRINT_STR && !is_bytes) {
print(env, "%.*s", str_len, str_data);
mp_printf(print, "%.*s", str_len, str_data);
} else {
if (is_bytes) {
print(env, "b");
mp_print_str(print, "b");
}
mp_str_print_quoted(print, env, str_data, str_len, is_bytes);
mp_str_print_quoted(print, str_data, str_len, is_bytes);
}
}
......@@ -145,8 +143,9 @@ mp_obj_t mp_obj_str_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw,
case 1: {
vstr_t vstr;
vstr_init(&vstr, 16);
mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, &vstr, args[0], PRINT_STR);
mp_print_t print;
vstr_init_print(&vstr, 16, &print);
mp_obj_print_helper(&print, args[0], PRINT_STR);
return mp_obj_new_str_from_vstr(type_in, &vstr);
}
......@@ -840,10 +839,8 @@ mp_obj_t mp_obj_str_format(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwa
GET_STR_DATA_LEN(args[0], str, len);
int arg_i = 0;
vstr_t vstr;
vstr_init(&vstr, 16);
pfenv_t pfenv_vstr;
pfenv_vstr.data = &vstr;
pfenv_vstr.print_strn = pfenv_vstr_add_strn;
mp_print_t print;
vstr_init_print(&vstr, 16, &print);
for (const byte *top = str + len; str < top; str++) {
if (*str == '}') {
......@@ -998,8 +995,9 @@ mp_obj_t mp_obj_str_format(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwa
}
}
vstr_t arg_vstr;
vstr_init(&arg_vstr, 16);
mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, &arg_vstr, arg, print_kind);
mp_print_t arg_print;
vstr_init_print(&arg_vstr, 16, &arg_print);
mp_obj_print_helper(&arg_print, arg, print_kind);
arg = mp_obj_new_str_from_vstr(&mp_type_str, &arg_vstr);
}
......@@ -1108,20 +1106,20 @@ mp_obj_t mp_obj_str_format(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwa
if (arg_looks_integer(arg)) {
switch (type) {
case 'b':
pfenv_print_mp_int(&pfenv_vstr, arg, 2, 'a', flags, fill, width, 0);
mp_print_mp_int(&print, arg, 2, 'a', flags, fill, width, 0);
continue;
case 'c':
{
char ch = mp_obj_get_int(arg);
pfenv_print_strn(&pfenv_vstr, &ch, 1, flags, fill, width);
mp_print_strn(&print, &ch, 1, flags, fill, width);
continue;
}
case '\0': // No explicit format type implies 'd'
case 'n': // I don't think we support locales in uPy so use 'd'
case 'd':
pfenv_print_mp_int(&pfenv_vstr, arg, 10, 'a', flags, fill, width, 0);
mp_print_mp_int(&print, arg, 10, 'a', flags, fill, width, 0);
continue;
case 'o':
......@@ -1129,12 +1127,12 @@ mp_obj_t mp_obj_str_format(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwa
flags |= PF_FLAG_SHOW_OCTAL_LETTER;
}
pfenv_print_mp_int(&pfenv_vstr, arg, 8, 'a', flags, fill, width, 0);
mp_print_mp_int(&print, arg, 8, 'a', flags, fill, width, 0);
continue;
case 'X':
case 'x':
pfenv_print_mp_int(&pfenv_vstr, arg, 16, type - ('X' - 'A'), flags, fill, width, 0);
mp_print_mp_int(&print, arg, 16, type - ('X' - 'A'), flags, fill, width, 0);
continue;
case 'e':
......@@ -1206,7 +1204,7 @@ mp_obj_t mp_obj_str_format(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwa
case 'F':
case 'g':
case 'G':
pfenv_print_float(&pfenv_vstr, mp_obj_get_float(arg), type, flags, fill, width, precision);
mp_print_float(&print, mp_obj_get_float(arg), type, flags, fill, width, precision);
break;
case '%':
......@@ -1216,7 +1214,7 @@ mp_obj_t mp_obj_str_format(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwa
#else
#define F100 100.0
#endif
pfenv_print_float(&pfenv_vstr, mp_obj_get_float(arg) * F100, 'f', flags, fill, width, precision);
mp_print_float(&print, mp_obj_get_float(arg) * F100, 'f', flags, fill, width, precision);
#undef F100
break;
#endif
......@@ -1244,7 +1242,7 @@ mp_obj_t mp_obj_str_format(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwa
switch (type) {
case '\0':
mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, &vstr, arg, PRINT_STR);
mp_obj_print_helper(&print, arg, PRINT_STR);
break;
case 's': {
......@@ -1256,7 +1254,7 @@ mp_obj_t mp_obj_str_format(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwa
if (slen > (mp_uint_t)precision) {
slen = precision;
}
pfenv_print_strn(&pfenv_vstr, s, slen, flags, fill, width);
mp_print_strn(&print, s, slen, flags, fill, width);
break;
}
......@@ -1282,10 +1280,8 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, mp_uint_t n_args, const mp_o
const byte *start_str = str;
int arg_i = 0;
vstr_t vstr;
vstr_init(&vstr, 16);
pfenv_t pfenv_vstr;
pfenv_vstr.data = &vstr;
pfenv_vstr.print_strn = pfenv_vstr_add_strn;
mp_print_t print;
vstr_init_print(&vstr, 16, &print);
for (const byte *top = str + len; str < top; str++) {
mp_obj_t arg = MP_OBJ_NULL;
......@@ -1389,10 +1385,10 @@ not_enough_args:
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
"%%c requires int or char"));
}
pfenv_print_strn(&pfenv_vstr, s, 1, flags, ' ', width);
mp_print_strn(&print, s, 1, flags, ' ', width);
} else if (arg_looks_integer(arg)) {
char ch = mp_obj_get_int(arg);
pfenv_print_strn(&pfenv_vstr, &ch, 1, flags, ' ', width);
mp_print_strn(&print, &ch, 1, flags, ' ', width);
} else {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
"integer required"));
......@@ -1402,7 +1398,7 @@ not_enough_args:
case 'd':
case 'i':
case 'u':
pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 10, 'a', flags, fill, width, prec);
mp_print_mp_int(&print, arg_as_int(arg), 10, 'a', flags, fill, width, prec);
break;
#if MICROPY_PY_BUILTINS_FLOAT
......@@ -1412,7 +1408,7 @@ not_enough_args:
case 'F':
case 'g':
case 'G':
pfenv_print_float(&pfenv_vstr, mp_obj_get_float(arg), *str, flags, fill, width, prec);
mp_print_float(&print, mp_obj_get_float(arg), *str, flags, fill, width, prec);
break;
#endif
......@@ -1420,16 +1416,16 @@ not_enough_args:
if (alt) {
flags |= (PF_FLAG_SHOW_PREFIX | PF_FLAG_SHOW_OCTAL_LETTER);
}
pfenv_print_mp_int(&pfenv_vstr, arg, 8, 'a', flags, fill, width, prec);
mp_print_mp_int(&print, arg, 8, 'a', flags, fill, width, prec);
break;
case 'r':
case 's':
{
vstr_t arg_vstr;
vstr_init(&arg_vstr, 16);
mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf,
&arg_vstr, arg, *str == 'r' ? PRINT_REPR : PRINT_STR);
mp_print_t arg_print;
vstr_init_print(&arg_vstr, 16, &arg_print);
mp_obj_print_helper(&arg_print, arg, *str == 'r' ? PRINT_REPR : PRINT_STR);
uint vlen = arg_vstr.len;
if (prec < 0) {
prec = vlen;
......@@ -1437,14 +1433,14 @@ not_enough_args:
if (vlen > (uint)prec) {
vlen = prec;
}
pfenv_print_strn(&pfenv_vstr, arg_vstr.buf, vlen, flags, ' ', width);
mp_print_strn(&print, arg_vstr.buf, vlen, flags, ' ', width);
vstr_clear(&arg_vstr);
break;
}
case 'X':
case 'x':
pfenv_print_mp_int(&pfenv_vstr, arg, 16, *str - ('X' - 'A'), flags | alt, fill, width, prec);
mp_print_mp_int(&print, arg, 16, *str - ('X' - 'A'), flags | alt, fill, width, prec);
break;
default:
......
......@@ -55,7 +55,7 @@ typedef struct _mp_obj_str_t {
else { str_len = ((mp_obj_str_t*)str_obj_in)->len; str_data = ((mp_obj_str_t*)str_obj_in)->data; }
mp_obj_t mp_obj_str_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args);
void mp_str_print_json(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, mp_uint_t str_len);
void mp_str_print_json(const mp_print_t *print, const byte *str_data, mp_uint_t str_len);
mp_obj_t mp_obj_str_format(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
mp_obj_t mp_obj_str_split(mp_uint_t n_args, const mp_obj_t *args);
mp_obj_t mp_obj_new_str_of_type(const mp_obj_type_t *type, const byte* data, mp_uint_t len);
......
......@@ -52,10 +52,10 @@ STATIC void check_stringio_is_open(const mp_obj_stringio_t *o) {
#define check_stringio_is_open(o)
#endif
STATIC void stringio_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
STATIC void stringio_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
mp_obj_stringio_t *self = self_in;
print(env, self->base.type == &mp_type_stringio ? "<io.StringIO 0x%x>" : "<io.BytesIO 0x%x>", self);
mp_printf(print, self->base.type == &mp_type_stringio ? "<io.StringIO 0x%x>" : "<io.BytesIO 0x%x>", self);
}
STATIC mp_uint_t stringio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
......
......@@ -33,7 +33,6 @@
#include "py/objlist.h"
#include "py/runtime0.h"
#include "py/runtime.h"
#include "py/pfenv.h"
#if MICROPY_PY_BUILTINS_STR_UNICODE
......@@ -42,7 +41,7 @@ STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str);
/******************************************************************************/
/* str */
STATIC void uni_print_quoted(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len) {
STATIC void uni_print_quoted(const mp_print_t *print, const byte *str_data, uint str_len) {
// this escapes characters, but it will be very slow to print (calling print many times)
bool has_single_quote = false;
bool has_double_quote = false;
......@@ -57,47 +56,47 @@ STATIC void uni_print_quoted(void (*print)(void *env, const char *fmt, ...), voi
if (has_single_quote && !has_double_quote) {
quote_char = '"';
}
print(env, "%c", quote_char);
mp_printf(print, "%c", quote_char);
const byte *s = str_data, *top = str_data + str_len;
while (s < top) {
unichar ch;
ch = utf8_get_char(s);
s = utf8_next_char(s);
if (ch == quote_char) {
print(env, "\\%c", quote_char);
mp_printf(print, "\\%c", quote_char);
} else if (ch == '\\') {
print(env, "\\\\");
mp_print_str(print, "\\\\");
} else if (32 <= ch && ch <= 126) {
print(env, "%c", ch);
mp_printf(print, "%c", ch);
} else if (ch == '\n') {
print(env, "\\n");
mp_print_str(print, "\\n");
} else if (ch == '\r') {
print(env, "\\r");
mp_print_str(print, "\\r");
}