Skip to content

Commit b69f9fa

Browse files
committed
Fix str.modulo when precision is specified.
1 parent 380f147 commit b69f9fa

4 files changed

Lines changed: 73 additions & 13 deletions

File tree

py/objstr.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,7 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
981981
if (arg_looks_integer(arg)) {
982982
switch (type) {
983983
case 'b':
984-
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 2, 'a', flags, fill, width);
984+
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 2, 'a', flags, fill, width, 0);
985985
continue;
986986

987987
case 'c':
@@ -994,20 +994,20 @@ mp_obj_t mp_obj_str_format(uint n_args, const mp_obj_t *args) {
994994
case '\0': // No explicit format type implies 'd'
995995
case 'n': // I don't think we support locales in uPy so use 'd'
996996
case 'd':
997-
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 10, 'a', flags, fill, width);
997+
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 10, 'a', flags, fill, width, 0);
998998
continue;
999999

10001000
case 'o':
10011001
if (flags & PF_FLAG_SHOW_PREFIX) {
10021002
flags |= PF_FLAG_SHOW_OCTAL_LETTER;
10031003
}
10041004

1005-
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width);
1005+
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width, 0);
10061006
continue;
10071007

10081008
case 'X':
10091009
case 'x':
1010-
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, type - ('X' - 'A'), flags, fill, width);
1010+
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, type - ('X' - 'A'), flags, fill, width, 0);
10111011
continue;
10121012

10131013
case 'e':
@@ -1255,7 +1255,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
12551255
case 'd':
12561256
case 'i':
12571257
case 'u':
1258-
pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 10, 'a', flags, fill, width);
1258+
pfenv_print_mp_int(&pfenv_vstr, arg_as_int(arg), 1, 10, 'a', flags, fill, width, prec);
12591259
break;
12601260

12611261
#if MICROPY_PY_BUILTINS_FLOAT
@@ -1273,7 +1273,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
12731273
if (alt) {
12741274
flags |= (PF_FLAG_SHOW_PREFIX | PF_FLAG_SHOW_OCTAL_LETTER);
12751275
}
1276-
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width);
1276+
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width, prec);
12771277
break;
12781278

12791279
case 'r':
@@ -1296,7 +1296,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
12961296

12971297
case 'X':
12981298
case 'x':
1299-
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, *str - ('X' - 'A'), flags | alt, fill, width);
1299+
pfenv_print_mp_int(&pfenv_vstr, arg, 1, 16, *str - ('X' - 'A'), flags | alt, fill, width, prec);
13001300
break;
13011301

13021302
default:

py/pfenv.c

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,10 @@ int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, in
9191
left_pad -= p;
9292
}
9393
}
94-
pfenv->print_strn(pfenv->data, str, len);
95-
total_chars_printed += len;
94+
if (len) {
95+
pfenv->print_strn(pfenv->data, str, len);
96+
total_chars_printed += len;
97+
}
9698
if (right_pad > 0) {
9799
total_chars_printed += right_pad;
98100
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
181183
return len;
182184
}
183185

184-
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) {
186+
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) {
185187
if (!MP_OBJ_IS_INT(x)) {
186188
// This will convert booleans to int, or raise an error for
187189
// non-integer types.
188190
x = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(x));
189191
}
190192

193+
if ((flags & (PF_FLAG_LEFT_ADJUST | PF_FLAG_CENTER_ADJUST)) == 0 && fill == '0') {
194+
if (prec > width) {
195+
width = prec;
196+
}
197+
prec = 0;
198+
}
191199
char prefix_buf[4];
192200
char *prefix = prefix_buf;
193201

@@ -230,6 +238,9 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int
230238
int fmt_size = 0;
231239
char *str;
232240

241+
if (prec > 1) {
242+
flags |= PF_FLAG_PAD_AFTER_SIGN;
243+
}
233244
char sign = '\0';
234245
if (flags & PF_FLAG_PAD_AFTER_SIGN) {
235246
// 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
245256
x, base, prefix, base_char, comma);
246257
}
247258

259+
int spaces_before = 0;
260+
int spaces_after = 0;
261+
262+
if (prec > 1) {
263+
// If prec was specified, then prec specifies the width to zero-pad the
264+
// the number to. This zero-padded number then gets left or right
265+
// aligned in width characters.
266+
267+
int prec_width = fmt_size; // The digits
268+
if (prec_width < prec) {
269+
prec_width = prec;
270+
}
271+
if (flags & PF_FLAG_PAD_AFTER_SIGN) {
272+
if (sign) {
273+
prec_width++;
274+
}
275+
prec_width += prefix_len;
276+
}
277+
if (prec_width < width) {
278+
if (flags & PF_FLAG_LEFT_ADJUST) {
279+
spaces_after = width - prec_width;
280+
} else {
281+
spaces_before = width - prec_width;
282+
}
283+
}
284+
fill = '0';
285+
flags &= ~PF_FLAG_LEFT_ADJUST;
286+
}
287+
248288
int len = 0;
289+
if (spaces_before) {
290+
len += pfenv_print_strn(pfenv, "", 0, 0, ' ', spaces_before);
291+
}
249292
if (flags & PF_FLAG_PAD_AFTER_SIGN) {
250293
// pad after sign implies pad after prefix as well.
251294
if (sign) {
@@ -257,9 +300,16 @@ int pfenv_print_mp_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int
257300
width -= prefix_len;
258301
}
259302
}
303+
if (prec > 1) {
304+
width = prec;
305+
}
260306

261307
len += pfenv_print_strn(pfenv, str, fmt_size, flags, fill, width);
262308

309+
if (spaces_after) {
310+
len += pfenv_print_strn(pfenv, "", 0, 0, ' ', spaces_after);
311+
}
312+
263313
if (buf != stack_buf) {
264314
m_free(buf, buf_size);
265315
}

py/pfenv.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ void pfenv_vstr_add_strn(void *data, const char *str, unsigned int len);
4545

4646
int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, int flags, char fill, int width);
4747
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);
48-
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);
48+
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);
4949
#if MICROPY_PY_BUILTINS_FLOAT
5050
int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, char fill, int width, int prec);
5151
#endif

tests/basics/string-format-modulo.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,18 @@
5151

5252
print("%*d" % (5, 10))
5353
print("%*.*d" % (2, 2, 20))
54-
# TODO: Formatted incorrectly
55-
#print("%*.*d" % (5, 8, 20))
54+
print("%*.*d" % (5, 8, 20))
55+
56+
print(">%8.4d<" % -12)
57+
print(">% 8.4d<" % -12)
58+
print(">%+8.4d<" % 12)
59+
print(">%+8.4d<" % -12)
60+
print(">%08.4d<" % -12)
61+
print(">%08.4d<" % 12)
62+
print(">%-8.4d<" % -12)
63+
print(">%-08.4d<" % -12)
64+
print(">%-+08.4d<" % -12)
65+
print(">%-+08.4d<" % 12)
5666

5767
# Cases when "*" used and there's not enough values total
5868
try:

0 commit comments

Comments
 (0)