From b69f9fa31f976cac4cdcb441612c8a72b10af457 Mon Sep 17 00:00:00 2001 From: Dave Hylands Date: Thu, 5 Jun 2014 23:09:02 -0700 Subject: [PATCH] Fix str.modulo when precision is specified. --- py/objstr.c | 14 +++---- py/pfenv.c | 56 ++++++++++++++++++++++++++-- py/pfenv.h | 2 +- tests/basics/string-format-modulo.py | 14 ++++++- 4 files changed, 73 insertions(+), 13 deletions(-) diff --git a/py/objstr.c b/py/objstr.c index 593c39cb09..4e70b00812 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -981,7 +981,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) { if (arg_looks_integer(arg)) { switch (type) { case 'b': - pfenv_print_mp_int(&pfenv_vstr, arg, 1, 2, 'a', flags, fill, width); + pfenv_print_mp_int(&pfenv_vstr, arg, 1, 2, 'a', flags, fill, width, 0); continue; case 'c': @@ -994,7 +994,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) { 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, 1, 10, 'a', flags, fill, width); + pfenv_print_mp_int(&pfenv_vstr, arg, 1, 10, 'a', flags, fill, width, 0); continue; case 'o': @@ -1002,12 +1002,12 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) { flags |= PF_FLAG_SHOW_OCTAL_LETTER; } - pfenv_print_mp_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width); + pfenv_print_mp_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width, 0); continue; case 'X': case 'x': - pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, type - ('X' - 'A'), flags, fill, width); + pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, type - ('X' - 'A'), flags, fill, width, 0); continue; case 'e': @@ -1255,7 +1255,7 @@ not_enough_args: case 'd': case 'i': case 'u': - pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 10, 'a', flags, fill, width); + pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 10, 'a', flags, fill, width, prec); break; #if MICROPY_PY_BUILTINS_FLOAT @@ -1273,7 +1273,7 @@ not_enough_args: if (alt) { flags |= (PF_FLAG_SHOW_PREFIX | PF_FLAG_SHOW_OCTAL_LETTER); } - pfenv_print_mp_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width); + pfenv_print_mp_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width, prec); break; case 'r': @@ -1296,7 +1296,7 @@ not_enough_args: case 'X': case 'x': - pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, *str - ('X' - 'A'), flags | alt, fill, width); + pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, *str - ('X' - 'A'), flags | alt, fill, width, prec); break; default: diff --git a/py/pfenv.c b/py/pfenv.c index e4db4da046..e631f8654a 100644 --- a/py/pfenv.c +++ b/py/pfenv.c @@ -91,8 +91,10 @@ int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, in left_pad -= p; } } - pfenv->print_strn(pfenv->data, str, len); - total_chars_printed += len; + if (len) { + pfenv->print_strn(pfenv->data, str, len); + total_chars_printed += len; + } if (right_pad > 0) { total_chars_printed += right_pad; while (right_pad > 0) { @@ -181,13 +183,19 @@ int pfenv_print_int(const pfenv_t *pfenv, machine_uint_t x, int sgn, int base, i return len; } -int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width) { +int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width, int prec) { if (!MP_OBJ_IS_INT(x)) { // This will convert booleans to int, or raise an error for // non-integer types. x = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(x)); } + if ((flags & (PF_FLAG_LEFT_ADJUST | PF_FLAG_CENTER_ADJUST)) == 0 && fill == '0') { + if (prec > width) { + width = prec; + } + prec = 0; + } char prefix_buf[4]; char *prefix = prefix_buf; @@ -230,6 +238,9 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int int fmt_size = 0; char *str; + if (prec > 1) { + flags |= PF_FLAG_PAD_AFTER_SIGN; + } char sign = '\0'; if (flags & PF_FLAG_PAD_AFTER_SIGN) { // We add the pad in this function, so since the pad goes after @@ -245,7 +256,39 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int x, base, prefix, base_char, comma); } + int spaces_before = 0; + int spaces_after = 0; + + if (prec > 1) { + // If prec was specified, then prec specifies the width to zero-pad the + // the number to. This zero-padded number then gets left or right + // aligned in width characters. + + int prec_width = fmt_size; // The digits + if (prec_width < prec) { + prec_width = prec; + } + if (flags & PF_FLAG_PAD_AFTER_SIGN) { + if (sign) { + prec_width++; + } + prec_width += prefix_len; + } + if (prec_width < width) { + if (flags & PF_FLAG_LEFT_ADJUST) { + spaces_after = width - prec_width; + } else { + spaces_before = width - prec_width; + } + } + fill = '0'; + flags &= ~PF_FLAG_LEFT_ADJUST; + } + int len = 0; + if (spaces_before) { + len += pfenv_print_strn(pfenv, "", 0, 0, ' ', spaces_before); + } if (flags & PF_FLAG_PAD_AFTER_SIGN) { // pad after sign implies pad after prefix as well. if (sign) { @@ -257,9 +300,16 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int width -= prefix_len; } } + if (prec > 1) { + width = prec; + } len += pfenv_print_strn(pfenv, str, fmt_size, flags, fill, width); + if (spaces_after) { + len += pfenv_print_strn(pfenv, "", 0, 0, ' ', spaces_after); + } + if (buf != stack_buf) { m_free(buf, buf_size); } diff --git a/py/pfenv.h b/py/pfenv.h index 2a3de6c32d..55eca6fed1 100644 --- a/py/pfenv.h +++ b/py/pfenv.h @@ -45,7 +45,7 @@ void pfenv_vstr_add_strn(void *data, const char *str, unsigned int len); int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, int flags, char fill, int width); int pfenv_print_int(const pfenv_t *pfenv, machine_uint_t x, int sgn, int base, int base_char, int flags, char fill, int width); -int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width); +int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width, int prec); #if MICROPY_PY_BUILTINS_FLOAT int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, char fill, int width, int prec); #endif diff --git a/tests/basics/string-format-modulo.py b/tests/basics/string-format-modulo.py index c8fdc06f68..f3f57b45ad 100644 --- a/tests/basics/string-format-modulo.py +++ b/tests/basics/string-format-modulo.py @@ -51,8 +51,18 @@ print("%#06x" % 18) print("%*d" % (5, 10)) print("%*.*d" % (2, 2, 20)) -# TODO: Formatted incorrectly -#print("%*.*d" % (5, 8, 20)) +print("%*.*d" % (5, 8, 20)) + +print(">%8.4d<" % -12) +print(">% 8.4d<" % -12) +print(">%+8.4d<" % 12) +print(">%+8.4d<" % -12) +print(">%08.4d<" % -12) +print(">%08.4d<" % 12) +print(">%-8.4d<" % -12) +print(">%-08.4d<" % -12) +print(">%-+08.4d<" % -12) +print(">%-+08.4d<" % 12) # Cases when "*" used and there's not enough values total try: