Skip to content
Snippets Groups Projects
Commit c4029e50 authored by Dave Hylands's avatar Dave Hylands
Browse files

Add string formatting support for longlong and mpz.

parent 6827f9fc
Branches
No related tags found
No related merge requests found
...@@ -1216,15 +1216,27 @@ uint mpz_as_str_size(const mpz_t *i, uint base) { ...@@ -1216,15 +1216,27 @@ uint mpz_as_str_size(const mpz_t *i, uint base) {
return i->len * DIG_SIZE / log_base2_floor[base] + 2 + 1; // +1 for null byte termination return i->len * DIG_SIZE / log_base2_floor[base] + 2 + 1; // +1 for null byte termination
} }
uint mpz_as_str_size_formatted(const mpz_t *i, uint base, const char *prefix, char comma) {
if (base < 2 || base > 32) {
return 0;
}
uint num_digits = i->len * DIG_SIZE / log_base2_floor[base] + 1;
uint num_commas = comma ? num_digits / 3: 0;
uint prefix_len = prefix ? strlen(prefix) : 0;
return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte
}
char *mpz_as_str(const mpz_t *i, uint base) { char *mpz_as_str(const mpz_t *i, uint base) {
char *s = m_new(char, mpz_as_str_size(i, base)); char *s = m_new(char, mpz_as_str_size(i, base));
mpz_as_str_inpl(i, base, s); mpz_as_str_inpl(i, base, "", 'a', 0, s);
return s; return s;
} }
// assumes enough space as calculated by mpz_as_str_size // assumes enough space as calculated by mpz_as_str_size
// returns length of string, not including null byte // returns length of string, not including null byte
uint mpz_as_str_inpl(const mpz_t *i, uint base, char *str) { uint mpz_as_str_inpl(const mpz_t *i, uint base, const char *prefix, char base_char, char comma, char *str) {
if (str == NULL || base < 2 || base > 32) { if (str == NULL || base < 2 || base > 32) {
str[0] = 0; str[0] = 0;
return 0; return 0;
...@@ -1232,10 +1244,15 @@ uint mpz_as_str_inpl(const mpz_t *i, uint base, char *str) { ...@@ -1232,10 +1244,15 @@ uint mpz_as_str_inpl(const mpz_t *i, uint base, char *str) {
uint ilen = i->len; uint ilen = i->len;
char *s = str;
if (ilen == 0) { if (ilen == 0) {
str[0] = '0'; if (prefix) {
str[1] = 0; while (*prefix)
return 1; *s++ = *prefix++;
}
*s++ = '0';
*s = '\0';
return s - str;
} }
// make a copy of mpz digits // make a copy of mpz digits
...@@ -1243,7 +1260,7 @@ uint mpz_as_str_inpl(const mpz_t *i, uint base, char *str) { ...@@ -1243,7 +1260,7 @@ uint mpz_as_str_inpl(const mpz_t *i, uint base, char *str) {
memcpy(dig, i->dig, ilen * sizeof(mpz_dig_t)); memcpy(dig, i->dig, ilen * sizeof(mpz_dig_t));
// convert // convert
char *s = str; char *last_comma = str;
bool done; bool done;
do { do {
mpz_dig_t *d = dig + ilen; mpz_dig_t *d = dig + ilen;
...@@ -1259,7 +1276,7 @@ uint mpz_as_str_inpl(const mpz_t *i, uint base, char *str) { ...@@ -1259,7 +1276,7 @@ uint mpz_as_str_inpl(const mpz_t *i, uint base, char *str) {
// convert to character // convert to character
a += '0'; a += '0';
if (a > '9') { if (a > '9') {
a += 'a' - '9' - 1; a += base_char - '9' - 1;
} }
*s++ = a; *s++ = a;
...@@ -1271,8 +1288,19 @@ uint mpz_as_str_inpl(const mpz_t *i, uint base, char *str) { ...@@ -1271,8 +1288,19 @@ uint mpz_as_str_inpl(const mpz_t *i, uint base, char *str) {
break; break;
} }
} }
} while (!done); if (comma && (s - last_comma) == 3) {
*s++ = comma;
last_comma = s;
}
}
while (!done);
if (prefix) {
const char *p = &prefix[strlen(prefix)];
while (p > prefix) {
*s++ = *--p;
}
}
if (i->neg != 0) { if (i->neg != 0) {
*s++ = '-'; *s++ = '-';
} }
...@@ -1284,7 +1312,7 @@ uint mpz_as_str_inpl(const mpz_t *i, uint base, char *str) { ...@@ -1284,7 +1312,7 @@ uint mpz_as_str_inpl(const mpz_t *i, uint base, char *str) {
*v = temp; *v = temp;
} }
s[0] = 0; // null termination *s = '\0'; // null termination
return s - str; return s - str;
} }
......
...@@ -76,5 +76,6 @@ bool mpz_as_int_checked(const mpz_t *z, machine_int_t *value); ...@@ -76,5 +76,6 @@ bool mpz_as_int_checked(const mpz_t *z, machine_int_t *value);
mp_float_t mpz_as_float(const mpz_t *z); mp_float_t mpz_as_float(const mpz_t *z);
#endif #endif
uint mpz_as_str_size(const mpz_t *z, uint base); uint mpz_as_str_size(const mpz_t *z, uint base);
uint mpz_as_str_size_formatted(const mpz_t *i, uint base, const char *prefix, char comma);
char *mpz_as_str(const mpz_t *z, uint base); char *mpz_as_str(const mpz_t *z, uint base);
uint mpz_as_str_inpl(const mpz_t *z, uint base, char *str); uint mpz_as_str_inpl(const mpz_t *z, uint base, const char *prefix, char base_char, char comma, char *str);
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <assert.h> #include <assert.h>
#include <string.h>
#include "nlr.h" #include "nlr.h"
#include "misc.h" #include "misc.h"
...@@ -53,13 +54,128 @@ STATIC mp_obj_t mp_obj_int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, co ...@@ -53,13 +54,128 @@ STATIC mp_obj_t mp_obj_int_make_new(mp_obj_t type_in, uint n_args, uint n_kw, co
} }
} }
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
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(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
if (MP_OBJ_IS_SMALL_INT(self_in)) { // The size of this buffer is rather arbitrary. If it's not large
print(env, INT_FMT, MP_OBJ_SMALL_INT_VALUE(self_in)); // enough, a dynamic one will be allocated.
char stack_buf[sizeof(machine_int_t) * 4];
char *buf = stack_buf;
int buf_size = sizeof(stack_buf);
int fmt_size;
char *str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size, self_in, 10, NULL, '\0', '\0');
print(env, "%s", str);
if (buf != stack_buf) {
m_free(buf, buf_size);
}
}
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE || MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
typedef mp_longint_impl_t fmt_int_t;
#else
typedef mp_small_int_t fmt_int_t;
#endif
static const uint log_base2_floor[] = {
0,
0, 1, 1, 2,
2, 2, 2, 3,
3, 3, 3, 3,
3, 3, 3, 4,
4, 4, 4, 4,
4, 4, 4, 4,
4, 4, 4, 4,
4, 4, 4, 5
};
uint int_as_str_size_formatted(uint base, const char *prefix, char comma) {
if (base < 2 || base > 32) {
return 0;
}
uint num_digits = sizeof(fmt_int_t) * 8 / log_base2_floor[base] + 1;
uint num_commas = comma ? num_digits / 3: 0;
uint prefix_len = prefix ? strlen(prefix) : 0;
return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte
}
// This routine expects you to pass in a buffer and size (in *buf and buf_size).
// If, for some reason, this buffer is too small, then it will allocate a
// buffer and return the allocated buffer and size in *buf and *buf_size. It
// is the callers responsibility to free this allocated buffer.
//
// The resulting formatted string will be returned from this function and the
// formatted size will be in *fmt_size.
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
int base, const char *prefix, char base_char, char comma) {
if (!MP_OBJ_IS_INT(self_in)) {
buf[0] = '\0';
*fmt_size = 0;
return *buf;
}
fmt_int_t num = mp_obj_get_int(self_in);
char sign = '\0';
if (num < 0) {
num = -num;
sign = '-';
}
uint needed_size = int_as_str_size_formatted(base, prefix, comma);
if (needed_size > *buf_size) {
*buf = m_new(char, needed_size);
*buf_size = needed_size;
}
char *str = *buf;
char *b = str + needed_size;
*(--b) = '\0';
char *last_comma = b;
if (num == 0) {
*(--b) = '0';
} else {
do {
int c = num % base;
num /= base;
if (c >= 10) {
c += base_char - 10;
} else {
c += '0';
}
*(--b) = c;
if (comma && num != 0 && b > str && (last_comma - b) == 3) {
*(--b) = comma;
last_comma = b;
}
}
while (b > str && num != 0);
} }
if (prefix) {
size_t prefix_len = strlen(prefix);
char *p = b - prefix_len;
if (p > str) {
b = p;
while (*prefix) {
*p++ = *prefix++;
} }
}
}
if (sign && b > str) {
*(--b) = sign;
}
*fmt_size = *buf + needed_size - b - 1;
return b;
}
bool mp_obj_int_is_positive(mp_obj_t self_in) {
return mp_obj_get_int(self_in) >= 0;
}
#endif // LONGLONG or NONE
#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE
// This is called for operations on SMALL_INT that are not handled by mp_unary_op // This is called for operations on SMALL_INT that are not handled by mp_unary_op
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) { mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
......
...@@ -8,6 +8,9 @@ typedef struct _mp_obj_int_t { ...@@ -8,6 +8,9 @@ typedef struct _mp_obj_int_t {
} mp_obj_int_t; } mp_obj_int_t;
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(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind);
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
int base, const char *prefix, char base_char, char comma);
bool mp_obj_int_is_positive(mp_obj_t self_in);
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in); mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in);
mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in); mp_obj_t mp_obj_int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);
mp_obj_t mp_obj_int_binary_op_extra_cases(int op, mp_obj_t lhs_in, mp_obj_t rhs_in); mp_obj_t mp_obj_int_binary_op_extra_cases(int op, mp_obj_t lhs_in, mp_obj_t rhs_in);
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include "nlr.h" #include "nlr.h"
#include "misc.h" #include "misc.h"
...@@ -21,15 +22,6 @@ ...@@ -21,15 +22,6 @@
#define SUFFIX "" #define SUFFIX ""
#endif #endif
void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
if (MP_OBJ_IS_SMALL_INT(self_in)) {
print(env, INT_FMT, MP_OBJ_SMALL_INT_VALUE(self_in));
} else {
mp_obj_int_t *self = self_in;
print(env, "%lld" SUFFIX, self->val);
}
}
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) { mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
mp_obj_int_t *o = o_in; mp_obj_int_t *o = o_in;
switch (op) { switch (op) {
......
...@@ -22,16 +22,47 @@ STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) { ...@@ -22,16 +22,47 @@ STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) {
return o; return o;
} }
void mp_obj_int_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { // This routine expects you to pass in a buffer and size (in *buf and buf_size).
// If, for some reason, this buffer is too small, then it will allocate a
// buffer and return the allocated buffer and size in *buf and *buf_size. It
// is the callers responsibility to free this allocated buffer.
//
// The resulting formatted string will be returned from this function and the
// formatted size will be in *fmt_size.
char *mp_obj_int_formatted(char **buf, int *buf_size, int *fmt_size, mp_obj_t self_in,
int base, const char *prefix, char base_char, char comma) {
mpz_t small_mpz;
mpz_t *mpz;
mpz_dig_t small_dig[(sizeof(mp_small_int_t) * 8 + MPZ_DIG_SIZE - 1) / MPZ_DIG_SIZE];
if (MP_OBJ_IS_SMALL_INT(self_in)) { if (MP_OBJ_IS_SMALL_INT(self_in)) {
print(env, INT_FMT, MP_OBJ_SMALL_INT_VALUE(self_in)); mpz_init_fixed_from_int(&small_mpz, small_dig,
sizeof(small_dig) / sizeof(small_dig[0]),
MP_OBJ_SMALL_INT_VALUE(self_in));
mpz = &small_mpz;
} else { } else {
// TODO would rather not allocate memory to print...
mp_obj_int_t *self = self_in; mp_obj_int_t *self = self_in;
char *str = mpz_as_str(&self->mpz, 10); mpz = &self->mpz;
print(env, "%s", str); }
m_free(str, 0);
uint needed_size = mpz_as_str_size_formatted(mpz, base, prefix, comma);
if (needed_size > *buf_size) {
*buf = m_new(char, needed_size);
*buf_size = needed_size;
}
char *str = *buf;
*fmt_size = mpz_as_str_inpl(mpz, base, prefix, base_char, comma, str);
return str;
} }
bool mp_obj_int_is_positive(mp_obj_t self_in) {
if (MP_OBJ_IS_SMALL_INT(self_in)) {
return MP_OBJ_SMALL_INT_VALUE(self_in) >= 0;
}
mp_obj_int_t *self = self_in;
return !self->mpz.neg;
} }
mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) { mp_obj_t mp_obj_int_unary_op(int op, mp_obj_t o_in) {
......
...@@ -562,13 +562,17 @@ static bool arg_looks_numeric(mp_obj_t arg) { ...@@ -562,13 +562,17 @@ static bool arg_looks_numeric(mp_obj_t arg) {
; ;
} }
static machine_int_t arg_as_int(mp_obj_t arg) { static mp_obj_t arg_as_int(mp_obj_t arg) {
#if MICROPY_ENABLE_FLOAT #if MICROPY_ENABLE_FLOAT
if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) { if (MP_OBJ_IS_TYPE(arg, &mp_type_float)) {
return mp_obj_get_float(arg);
// TODO: Needs a way to construct an mpz integer from a float
mp_small_int_t num = mp_obj_get_float(arg);
return MP_OBJ_NEW_SMALL_INT(num);
} }
#endif #endif
return mp_obj_get_int(arg); return arg;
} }
mp_obj_t str_format(uint n_args, const mp_obj_t *args) { mp_obj_t str_format(uint n_args, const mp_obj_t *args) {
...@@ -788,7 +792,7 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) { ...@@ -788,7 +792,7 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) {
if (arg_looks_integer(arg)) { if (arg_looks_integer(arg)) {
switch (type) { switch (type) {
case 'b': case 'b':
pfenv_print_int(&pfenv_vstr, mp_obj_get_int(arg), 1, 2, 'a', flags, fill, width); pfenv_print_int(&pfenv_vstr, arg, 1, 2, 'a', flags, fill, width);
continue; continue;
case 'c': case 'c':
...@@ -801,19 +805,23 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) { ...@@ -801,19 +805,23 @@ mp_obj_t str_format(uint n_args, const mp_obj_t *args) {
case '\0': // No explicit format type implies 'd' case '\0': // No explicit format type implies 'd'
case 'n': // I don't think we support locales in uPy so use 'd' case 'n': // I don't think we support locales in uPy so use 'd'
case 'd': case 'd':
pfenv_print_int(&pfenv_vstr, mp_obj_get_int(arg), 1, 10, 'a', flags, fill, width); pfenv_print_int(&pfenv_vstr, arg, 1, 10, 'a', flags, fill, width);
continue; continue;
case 'o': case 'o':
pfenv_print_int(&pfenv_vstr, mp_obj_get_int(arg), 1, 8, 'a', flags, fill, width); if (flags & PF_FLAG_SHOW_PREFIX) {
flags |= PF_FLAG_SHOW_OCTAL_LETTER;
}
pfenv_print_int(&pfenv_vstr, arg, 1, 8, 'a', flags, fill, width);
continue; continue;
case 'x': case 'x':
pfenv_print_int(&pfenv_vstr, mp_obj_get_int(arg), 1, 16, 'a', flags, fill, width); pfenv_print_int(&pfenv_vstr, arg, 1, 16, 'a', flags, fill, width);
continue; continue;
case 'X': case 'X':
pfenv_print_int(&pfenv_vstr, mp_obj_get_int(arg), 1, 16, 'A', flags, fill, width); pfenv_print_int(&pfenv_vstr, arg, 1, 16, 'A', flags, fill, width);
continue; continue;
case 'e': case 'e':
...@@ -1050,7 +1058,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t ...@@ -1050,7 +1058,7 @@ STATIC mp_obj_t str_modulo_format(mp_obj_t pattern, uint n_args, const mp_obj_t
case 'o': case 'o':
if (alt) { if (alt) {
flags |= PF_FLAG_SHOW_PREFIX; flags |= (PF_FLAG_SHOW_PREFIX | PF_FLAG_SHOW_OCTAL_LETTER);
} }
pfenv_print_int(&pfenv_vstr, arg_as_int(arg), 1, 8, 'a', flags, fill, width); pfenv_print_int(&pfenv_vstr, arg_as_int(arg), 1, 8, 'a', flags, fill, width);
break; break;
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include "mpconfig.h" #include "mpconfig.h"
#include "qstr.h" #include "qstr.h"
#include "obj.h" #include "obj.h"
#include "mpz.h"
#include "objint.h"
#include "pfenv.h" #include "pfenv.h"
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
...@@ -79,71 +81,88 @@ int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, in ...@@ -79,71 +81,88 @@ int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, in
// We can use 16 characters for 32-bit and 32 characters for 64-bit // We can use 16 characters for 32-bit and 32 characters for 64-bit
#define INT_BUF_SIZE (sizeof(machine_int_t) * 4) #define INT_BUF_SIZE (sizeof(machine_int_t) * 4)
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_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width) {
char sign = 0; if (!MP_OBJ_IS_INT(x)) {
if (sgn) { // This will convert booleans to int, or raise an error for
if ((machine_int_t)x < 0) { // non-integer types.
sign = '-'; x = MP_OBJ_NEW_SMALL_INT(mp_obj_get_int(x));
x = -x;
} else if (flags & PF_FLAG_SHOW_SIGN) {
sign = '+';
} else if (flags & PF_FLAG_SPACE_SIGN) {
sign = ' ';
}
} }
char buf[INT_BUF_SIZE]; char prefix_buf[4];
char *b = buf + INT_BUF_SIZE; char *prefix = prefix_buf;
if (x == 0) { if (mp_obj_int_is_positive(x)) {
*(--b) = '0'; if (flags & PF_FLAG_SHOW_SIGN) {
} else { *prefix++ = '+';
do { } else if (flags & PF_FLAG_SPACE_SIGN) {
int c = x % base; *prefix++ = ' ';
x /= base;
if (c >= 10) {
c += base_char - 10;
} else {
c += '0';
} }
*(--b) = c;
} while (b > buf && x != 0);
} }
char prefix_char = '\0';
if (flags & PF_FLAG_SHOW_PREFIX) { if (flags & PF_FLAG_SHOW_PREFIX) {
if (base == 2) { if (base == 2) {
prefix_char = base_char + 'b' - 'a'; *prefix++ = '0';
*prefix++ = base_char + 'b' - 'a';
} else if (base == 8) { } else if (base == 8) {
prefix_char = base_char + 'o' - 'a'; *prefix++ = '0';
if (flags & PF_FLAG_SHOW_OCTAL_LETTER) {
*prefix++ = base_char + 'o' - 'a';
}
} else if (base == 16) { } else if (base == 16) {
prefix_char = base_char + 'x' - 'a'; *prefix++ = '0';
*prefix++ = base_char + 'x' - 'a';
}
}
*prefix = '\0';
int prefix_len = prefix - prefix_buf;
prefix = prefix_buf;
char comma = '\0';
if (flags & PF_FLAG_SHOW_COMMA) {
comma = ',';
}
// The size of this buffer is rather arbitrary. If it's not large
// enough, a dynamic one will be allocated.
char stack_buf[sizeof(machine_int_t) * 4];
char *buf = stack_buf;
int buf_size = sizeof(stack_buf);
int fmt_size = 0;
char *str;
char sign = '\0';
if (flags & PF_FLAG_PAD_AFTER_SIGN) {
// We add the pad in this function, so since the pad goes after
// the sign & prefix, we format without a prefix
str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size,
x, base, NULL, base_char, comma);
if (*str == '-') {
sign = *str++;
fmt_size--;
} }
} else {
str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size,
x, base, prefix, base_char, comma);
} }
int len = 0; int len = 0;
if (flags & PF_FLAG_PAD_AFTER_SIGN) { if (flags & PF_FLAG_PAD_AFTER_SIGN) {
// pad after sign implies pad after prefix as well.
if (sign) { if (sign) {
len += pfenv_print_strn(pfenv, &sign, 1, flags, fill, 1); len += pfenv_print_strn(pfenv, &sign, 1, 0, 0, 1);
width--; width--;
} }
if (prefix_char) { if (prefix_len) {
len += pfenv_print_strn(pfenv, "0", 1, flags, fill, 1); len += pfenv_print_strn(pfenv, prefix, prefix_len, 0, 0, 1);
len += pfenv_print_strn(pfenv, &prefix_char, 1, flags, fill, 1); width -= prefix_len;
width -= 2;
}
} else {
if (prefix_char && b > &buf[1]) {
*(--b) = prefix_char;
*(--b) = '0';
}
if (sign && b > buf) {
*(--b) = sign;
} }
} }
len += pfenv_print_strn(pfenv, b, buf + INT_BUF_SIZE - b, flags, fill, width); len += pfenv_print_strn(pfenv, str, fmt_size, flags, fill, width);
if (buf != stack_buf) {
m_free(buf, buf_size);
}
return len; return len;
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#define PF_FLAG_CENTER_ADJUST (0x080) #define PF_FLAG_CENTER_ADJUST (0x080)
#define PF_FLAG_ADD_PERCENT (0x100) #define PF_FLAG_ADD_PERCENT (0x100)
#define PF_FLAG_PAD_NAN_INF (0x200) #define PF_FLAG_PAD_NAN_INF (0x200)
#define PF_FLAG_SHOW_OCTAL_LETTER (0x400)
typedef struct _pfenv_t { typedef struct _pfenv_t {
void *data; void *data;
...@@ -17,7 +18,7 @@ typedef struct _pfenv_t { ...@@ -17,7 +18,7 @@ typedef struct _pfenv_t {
void pfenv_vstr_add_strn(void *data, const char *str, unsigned int len); 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_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_int(const pfenv_t *pfenv, mp_obj_t x, int sgn, int base, int base_char, int flags, char fill, int width);
#if MICROPY_ENABLE_FLOAT #if MICROPY_ENABLE_FLOAT
int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, char fill, int width, int prec); int pfenv_print_float(const pfenv_t *pfenv, mp_float_t f, char fmt, int flags, char fill, int width, int prec);
#endif #endif
...@@ -53,6 +53,7 @@ print("%X" % 18) ...@@ -53,6 +53,7 @@ print("%X" % 18)
print("%X" % 18.0) print("%X" % 18.0)
print("%#x" % 18) print("%#x" % 18)
print("%#X" % 18) print("%#X" % 18)
print("%#6o" % 18)
print("%#6x" % 18) print("%#6x" % 18)
print("%#06x" % 18) print("%#06x" % 18)
print("%e" % 1.23456) print("%e" % 1.23456)
......
...@@ -24,11 +24,19 @@ test("{:4o}", 123) ...@@ -24,11 +24,19 @@ test("{:4o}", 123)
test("{:4x}", 123) test("{:4x}", 123)
test("{:4X}", 123) test("{:4X}", 123)
test("{:4,d}", 12345678)
test("{:#4b}", 10) test("{:#4b}", 10)
test("{:#4o}", 123) test("{:#4o}", 123)
test("{:#4x}", 123) test("{:#4x}", 123)
test("{:#4X}", 123) test("{:#4X}", 123)
test("{:#4d}", 0)
test("{:#4b}", 0)
test("{:#4o}", 0)
test("{:#4x}", 0)
test("{:#4X}", 0)
test("{:<6s}", "ab") test("{:<6s}", "ab")
test("{:>6s}", "ab") test("{:>6s}", "ab")
test("{:^6s}", "ab") test("{:^6s}", "ab")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment