summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authorManuel Novoa III <mjn3@codepoet.org>2002-11-03 20:13:27 +0000
committerManuel Novoa III <mjn3@codepoet.org>2002-11-03 20:13:27 +0000
commit868df46adcf4637aadd773cbe42521ef980370b2 (patch)
tree512d59a1be375a21a8419d604342354886a7a8a7 /libc
parent9333e4142260e5451277a7b50b49b9c636a93b64 (diff)
Implement locale-specific grouping in printf for base 10 integer conversions
when the grouping flag "'" is specified. Grouping for floating point values may wait until I do a rewrite of the floating pt to string code...
Diffstat (limited to 'libc')
-rw-r--r--libc/stdio/printf.c24
-rw-r--r--libc/stdio/stdio.c75
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_stdio.h1
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;