diff options
-rw-r--r-- | libc/stdio/printf.c | 24 | ||||
-rw-r--r-- | libc/stdio/stdio.c | 75 | ||||
-rw-r--r-- | libc/sysdeps/linux/common/bits/uClibc_stdio.h | 1 |
3 files changed, 95 insertions, 5 deletions
diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c index d593f769c..d08ac56b0 100644 --- a/libc/stdio/printf.c +++ b/libc/stdio/printf.c @@ -1103,10 +1103,18 @@ int _do_one_spec(FILE * __restrict stream, register ppfs_t *ppfs, int *count) size_t slen; int base; int numpad; + int alphacase; int numfill = 0; /* TODO: fix */ int prefix_num = PREFIX_NONE; char padchar = ' '; - char buf[64]; +#ifdef __UCLIBC_MJN3_ONLY__ +#warning REMINDER: buf size +#endif + /* TODO: buf needs to be big enough for any possible error return strings + * and also for any locale-grouped long long integer strings generated. + * This should be large enough for any of the current archs/locales, but + * eventually this should be handled robustly. */ + char buf[128]; #ifdef NDEBUG _ppfs_parsespec(ppfs); @@ -1147,8 +1155,16 @@ int _do_one_spec(FILE * __restrict stream, register ppfs_t *ppfs, int *count) return 0; } if (ppfs->conv_num <= CONV_i) { /* pointer or (un)signed int */ - base = spec_base[(int)(ppfs->conv_num - CONV_p)]; + alphacase = __UIM_LOWER; + if (((base = spec_base[(int)(ppfs->conv_num - CONV_p)]) == 10) + && (PRINT_INFO_FLAG_VAL(&(ppfs->info),group)) + ) { + alphacase = __UIM_GROUP; + } if (ppfs->conv_num <= CONV_u) { /* pointer or unsigned int */ + if (ppfs->conv_num == CONV_X) { + alphacase = __UIM_UPPER; + } if (ppfs->conv_num == CONV_p) { /* pointer */ prefix_num = PREFIX_LWR_X; } else { /* unsigned int */ @@ -1162,9 +1178,7 @@ int _do_one_spec(FILE * __restrict stream, register ppfs_t *ppfs, int *count) s = _uintmaxtostr(buf + sizeof(buf) - 1, (uintmax_t) _load_inttype(*argtype & __PA_INTMASK, - *argptr, base), base, - ((ppfs->conv_num == CONV_X) - ? __UIM_UPPER : __UIM_LOWER)); + *argptr, base), base, alphacase); if (ppfs->conv_num > CONV_u) { /* signed int */ if (*s == '-') { PRINT_INFO_SET_FLAG(&(ppfs->info),showsign); diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c index b0b046900..f75011aec 100644 --- a/libc/stdio/stdio.c +++ b/libc/stdio/stdio.c @@ -3308,6 +3308,15 @@ void _stdio_fdout(int fd, ...) #define INTERNAL_DIV_MOD #endif +#ifdef __UCLIBC_MJN3_ONLY__ +#warning REMINDER: move _uintmaxtostr to locale.c??? +#endif +#include <locale.h> + +#ifndef __LOCALE_C_ONLY +#define CUR_LOCALE (__global_locale) +#endif /* __LOCALE_C_ONLY */ + char *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval, int base, __UIM_CASE alphacase) { @@ -3316,6 +3325,11 @@ char *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval, #ifdef INTERNAL_DIV_MOD unsigned int H, L, high, low, rh; #endif +#ifndef __LOCALE_C_ONLY + int grouping; + size_t gslen; /* This does not need to be initialized. */ + const char *g; /* This does not need to be initialized. */ +#endif /* __LOCALE_C_ONLY */ negative = 0; if (base < 0) { /* signed value */ @@ -3329,10 +3343,46 @@ char *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval, /* this is an internal routine -- we shouldn't need to check this */ assert(!((base < 2) || (base > 36))); +#ifndef __LOCALE_C_ONLY + grouping = -1; + if (alphacase == __UIM_GROUP) { + assert(base == 10); + if (*(g = CUR_LOCALE.grouping) + && ((gslen = strlen(CUR_LOCALE.thousands_sep)) > 0) + ) { + grouping = *g; + } + } +#endif /* __LOCALE_C_ONLY */ + *bufend = '\0'; #ifndef INTERNAL_DIV_MOD do { +#ifndef __LOCALE_C_ONLY + if (!grouping) { /* Finished a group. */ +#ifdef __UCLIBC_MJN3_ONLY__ +#warning REMINDER: decide about memcpy in _uintmaxtostr +#endif +#if 0 + bufend -= gslen; + memcpy(bufend, CUR_LOCALE.thousands_sep, gslen); +#else + grouping = gslen; + do { + *--bufend = CUR_LOCALE.thousands_sep[--grouping]; + } while (grouping); +#endif + if (g[1] != 0) { /* g[1] == 0 means repeat last grouping. */ + /* Note: g[1] == -1 means no further grouping. But since + * we'll never wrap around, we can set grouping to -1 without + * fear of */ + ++g; + } + grouping = *g; + } + --grouping; +#endif /* __LOCALE_C_ONLY */ digit = uval % base; uval /= base; @@ -3351,6 +3401,31 @@ char *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval, high = (unsigned int) (uval >> (sizeof(unsigned int) * CHAR_BIT)); do { +#ifndef __LOCALE_C_ONLY + if (!grouping) { /* Finished a group. */ +#ifdef __UCLIBC_MJN3_ONLY__ +#warning REMINDER: decide about memcpy in _uintmaxtostr +#endif +#if 0 + bufend -= gslen; + memcpy(bufend, CUR_LOCALE.thousands_sep, gslen); +#else + grouping = gslen; + do { + *--bufend = CUR_LOCALE.thousands_sep[--grouping]; + } while (grouping); +#endif + if (g[1] != 0) { /* g[1] == 0 means repeat last grouping. */ + /* Note: g[1] == -1 means no further grouping. But since + * we'll never wrap around, we can set grouping to -1 without + * fear of */ + ++g; + } + grouping = *g; + } + --grouping; +#endif /* __LOCALE_C_ONLY */ + rh = high % base; high /= base; digit = (low % base) + (L * rh); diff --git a/libc/sysdeps/linux/common/bits/uClibc_stdio.h b/libc/sysdeps/linux/common/bits/uClibc_stdio.h index 83c082f75..f6d27142e 100644 --- a/libc/sysdeps/linux/common/bits/uClibc_stdio.h +++ b/libc/sysdeps/linux/common/bits/uClibc_stdio.h @@ -463,6 +463,7 @@ extern void __stdio_validate_FILE(FILE *stream); typedef enum { __UIM_DECIMAL = 0, + __UIM_GROUP = ',', /* Base 10 locale-dependent grouping. */ __UIM_LOWER = 'a' - 10, __UIM_UPPER = 'A' - 10, } __UIM_CASE; |