summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog21
-rw-r--r--locale/Makefile2
-rw-r--r--locale/programs/ld-ctype.c29
-rw-r--r--localedata/ChangeLog11
-rw-r--r--localedata/Makefile6
-rw-r--r--localedata/tests/test7.cm86
-rw-r--r--localedata/tests/test7.def25
-rw-r--r--localedata/tst-digits.c81
-rwxr-xr-xlocaledata/tst-locale.sh4
-rw-r--r--stdio-common/Depend1
-rw-r--r--stdio-common/_i18n_itoa.c266
-rw-r--r--stdio-common/_i18n_itoa.h41
-rw-r--r--stdio-common/_i18n_itowa.c267
-rw-r--r--stdio-common/_i18n_number.h (renamed from stdio-common/_i18n_itowa.h)48
-rw-r--r--stdio-common/bug13.c2
-rw-r--r--stdio-common/printf-parse.h78
-rw-r--r--stdio-common/vfprintf.c85
17 files changed, 372 insertions, 681 deletions
diff --git a/ChangeLog b/ChangeLog
index 269b5b8329..8f51dc8606 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2000-07-28  Ulrich Drepper  <drepper@redhat.com>
+
+	* stdio-common/_i18n_itoa.c: Removed.
+	* stdio-common/_i18n_itoa.h: Removed.
+	* stdio-common/_i18n_itowa.c: Removed.
+	* stdio-common/_i18n_itowa.h: Removed.
+	* stdio-common/_i18n_number.h: New file.
+	* stdio-common/Depend: New file.
+	* stdio-common/printf-parse.h: Handle I modifier correctly.  Optimize.
+	* stdio-common/vfprintf.c: Rewrite buffer handling for integer
+	printing.  Change printing of numbers with locale specific digits to
+	use new code in _i18n_number.h.
+
+	* stdio-common/bug13.c: Improve messages.
+
+	* locale/programs/ld-ctype.c (ctype_read): Improve error message.
+	(set_class_defaults): Always search also for Uxxxx names.
+	Detect insufficient number of outdigits.
+
+	* locale/Makefile (C-translit.h): Use mv not $(move-if-changed).
+
 2000-07-27  Bruno Haible  <haible@clisp.cons.org>
 
 	* locale/C-ctype.c (_nl_C_LC_CTYPE): Swap the two names in
diff --git a/locale/Makefile b/locale/Makefile
index 2825a697c2..5d7594a853 100644
--- a/locale/Makefile
+++ b/locale/Makefile
@@ -76,7 +76,7 @@ $(objpfx)localedef $(objpfx)locale: $(lib-modules:%=$(objpfx)%.o)
 
 C-translit.h: C-translit.h.in gen-translit.pl
 	$(PERL) gen-translit.pl < $< > $@.tmp
-	$(move-if-change) $@.tmp $@
+	mv -f $@.tmp $@
 ifeq ($(with-cvs),yes)
 	test ! -d CVS || cvs $(CVSOPTS) commit -mRegenerated $@
 endif
diff --git a/locale/programs/ld-ctype.c b/locale/programs/ld-ctype.c
index ebfc1e42a4..1c1c492cb0 100644
--- a/locale/programs/ld-ctype.c
+++ b/locale/programs/ld-ctype.c
@@ -2274,7 +2274,8 @@ ctype_read (struct linereader *ldfile, struct localedef_t *result,
 			  lr_error (ldfile, _("\
 %s: field `%s' does not contain exactly ten entries"),
 			    "LC_CTYPE", "outdigit");
-			  goto err_label;
+			  lr_ignore_rest (ldfile, 0);
+			  break;
 			}
 
 		      ctype->mboutdigits[ctype->outdigits_act] = seq;
@@ -2781,6 +2782,12 @@ set_class_defaults (struct locale_ctype_t *ctype, struct charmap_t *charmap,
 	  seq = charmap_find_value (charmap, tmp, 1);
 	  if (seq == NULL)
 	    {
+	      char buf[10];
+	      sprintf (buf, "U%08X", ch);
+	      seq = charmap_find_value (charmap, buf, 9);
+	    }
+	  if (seq == NULL)
+	    {
 	      if (!be_quiet)
 		error (0, 0, _("\
 %s: character `%s' not defined in charmap while needed as default value"),
@@ -3133,6 +3140,12 @@ character `%s' not defined while needed as default value"),
 	  seq_from = charmap_find_value (charmap, &tmp[1], 1);
 	  if (seq_from == NULL)
 	    {
+	      char buf[10];
+	      sprintf (buf, "U%08X", ch);
+	      seq_from = charmap_find_value (charmap, buf, 9);
+	    }
+	  if (seq_from == NULL)
+	    {
 	      if (!be_quiet)
 		error (0, 0, _("\
 %s: character `%s' not defined while needed as default value"),
@@ -3152,6 +3165,12 @@ character `%s' not defined while needed as default value"),
 	      seq_to = charmap_find_value (charmap, &tmp[1], 1);
 	      if (seq_to == NULL)
 		{
+		  char buf[10];
+		  sprintf (buf, "U%08X", ch + ('A' - 'a'));
+		  seq_to = charmap_find_value (charmap, buf, 9);
+		}
+	      if (seq_to == NULL)
+		{
 		  if (!be_quiet)
 		    error (0, 0, _("\
 %s: character `%s' not defined while needed as default value"),
@@ -3191,9 +3210,13 @@ character `%s' not defined while needed as default value"),
 	  ctype->map256_collection[1][ctype->map256_collection[0][cnt]] = cnt;
     }
 
-  if (ctype->outdigits_act == 0)
+  if (ctype->outdigits_act != 10)
     {
-      for (cnt = 0; cnt < 10; ++cnt)
+      if (ctype->outdigits_act != 0)
+	error (0,0, _("%s: field `%s' does not contain exactly ten entries"),
+	       "LC_CTYPE", "outdigit");
+
+      for (cnt = ctype->outdigits_act; cnt < 10; ++cnt)
 	{
 	  ctype->mboutdigits[cnt] = charmap_find_symbol (charmap,
 							 digits + cnt, 1);
diff --git a/localedata/ChangeLog b/localedata/ChangeLog
index 3125e95607..380a53fe5c 100644
--- a/localedata/ChangeLog
+++ b/localedata/ChangeLog
@@ -1,3 +1,14 @@
+2000-07-28  Ulrich Drepper  <drepper@redhat.com>
+
+	* Makefile (ld-test-names): Add test7.
+	(tests): Add tst-digits.  Add dependency and environment variable.
+	* tst-digits.c: New file.
+	* tst-locale.sh: Generate test7 locale.
+	* tests/test7.cm: New file.
+	* tests/test7.def: New file.
+
+	* tst-locale.sh: Add dropped test6 locale.
+
 2000-07-27  Bruno Haible  <haible@clisp.cons.org>
 
 	* tests-mbwc/tgn_locdef.h (TST_LOC_C): New macro.
diff --git a/localedata/Makefile b/localedata/Makefile
index a5bdca0947..e9aec39c67 100644
--- a/localedata/Makefile
+++ b/localedata/Makefile
@@ -50,7 +50,7 @@ test-input := de_DE.ISO-8859-1 en_US.ISO-8859-1
 test-input-data = $(addsuffix .in, $(basename $(test-input)))
 test-output := $(foreach s, .out .xout, \
 			 $(addsuffix $s, $(basename $(test-input))))
-ld-test-names := test1 test2 test3 test4 test5 test6
+ld-test-names := test1 test2 test3 test4 test5 test6 test7
 ld-test-srcs := $(addprefix tests/,$(addsuffix .cm,$(ld-test-names)) \
 				   $(addsuffix .def,$(ld-test-names)) \
 				   $(addsuffix .ds,test5 test6) \
@@ -92,7 +92,7 @@ locale_test_suite := tst_iswalnum tst_iswalpha tst_iswcntrl            \
 		     tst_wcsxfrm tst_wctob tst_wctomb tst_wctrans      \
 		     tst_wctype tst_wcwidth
 
-tests = $(locale_test_suite)
+tests = $(locale_test_suite) tst-digits
 endif
 
 # Files to install.
@@ -176,6 +176,7 @@ $(objpfx)tst-langinfo.out: tst-langinfo.sh $(objpfx)tst-langinfo \
 			$(objpfx)sort-test.out \
 			$(addprefix $(objpfx),$(CTYPE_FILES))
 	$(SHELL) -e $< $(common-objpfx) '$(built-program-cmd)'
+$(objpfx)tst-digits.out: $(objpfx)tst-locale.out
 endif
 
 # Sometimes the whole collection of locale files should be installed.
@@ -241,3 +242,4 @@ tst_wctomb-ENV = $(TEST_MBWC_ENV)
 tst_wctrans-ENV = $(TEST_MBWC_ENV)
 tst_wctype-ENV = $(TEST_MBWC_ENV)
 tst_wcwidth-ENV = $(TEST_MBWC_ENV)
+tst-digits-ENV = $(TEST_MBWC_ENV)
diff --git a/localedata/tests/test7.cm b/localedata/tests/test7.cm
new file mode 100644
index 0000000000..207197e020
--- /dev/null
+++ b/localedata/tests/test7.cm
@@ -0,0 +1,86 @@
+<code_set_name> test7
+<mb_cur_min> 1
+<mb_cur_max> 3
+
+CHARMAP
+<U0009>                \x09
+<U000A>                \x0a
+<U000B>                \x0b
+<U000C>                \x0c
+<U000D>                \x0d
+<U0020>                \x20
+<U002C>                \x2c
+<U002E>                \x2e
+<U0030>                \x30
+<U0031>                \x31
+<U0032>                \x32
+<U0033>                \x33
+<U0034>                \x34
+<U0035>                \x35
+<U0036>                \x36
+<U0037>                \x37
+<U0038>                \x38
+<U0039>                \x39
+<U0061>                \x41
+<U0062>                \x42
+<U0063>                \x43
+<U0064>                \x44
+<U0065>                \x45
+<U0066>                \x46
+<U0067>                \x47
+<U0068>                \x48
+<U0069>                \x49
+<U006A>                \x4A
+<U006B>                \x4B
+<U006C>                \x4C
+<U006D>                \x4D
+<U006E>                \x4E
+<U006F>                \x4F
+<U0070>                \x50
+<U0071>                \x51
+<U0072>                \x52
+<U0073>                \x53
+<U0074>                \x54
+<U0075>                \x55
+<U0076>                \x56
+<U0077>                \x57
+<U0078>                \x58
+<U0079>                \x59
+<U007A>                \x5A
+<U0041>                \x61
+<U0042>                \x62
+<U0043>                \x63
+<U0044>                \x64
+<U0045>                \x65
+<U0046>                \x66
+<U0047>                \x67
+<U0048>                \x68
+<U0049>                \x69
+<U004A>                \x6a
+<U004B>                \x6b
+<U004C>                \x6c
+<U004D>                \x6d
+<U004E>                \x6e
+<U004F>                \x6f
+<U0050>                \x70
+<U0051>                \x71
+<U0052>                \x72
+<U0053>                \x73
+<U0054>                \x74
+<U0055>                \x75
+<U0056>                \x76
+<U0057>                \x77
+<U0058>                \x78
+<U0059>                \x79
+<U005A>                \x7a
+<U2080>                \xe2\x82\x80
+<U2081>                \xe2\x82\x81
+<U2082>                \xe2\x82\x82
+<U2083>                \xe2\x82\x83
+<U2084>                \xe2\x82\x84
+<U2085>                \xe2\x82\x85
+<U2086>                \xe2\x82\x86
+<U2087>                \xe2\x82\x87
+<U2088>                \xe2\x82\x88
+<U2089>                \xe2\x82\x89
+END CHARMAP
diff --git a/localedata/tests/test7.def b/localedata/tests/test7.def
new file mode 100644
index 0000000000..8f43b361f6
--- /dev/null
+++ b/localedata/tests/test7.def
@@ -0,0 +1,25 @@
+LC_CTYPE
+lower <U0061>;<U0062>;<U0063>;<U0064>;<U0065>;<U0066>;<U0067>;<U0068>;\
+      <U0069>;<U006A>;<U006B>;<U006C>;<U006D>;<U006E>;<U006F>;<U0070>;\
+      <U0071>;<U0072>;<U0073>;<U0074>;<U0075>;<U0076>;<U0077>;<U0078>;\
+      <U0079>;<U007A>
+
+upper <U0041>;<U0042>;<U0043>;<U0044>;<U0045>;<U0046>;<U0047>;<U0048>;\
+      <U0049>;<U004A>;<U004B>;<U004C>;<U004D>;<U004E>;<U004F>;<U0050>;\
+      <U0051>;<U0052>;<U0053>;<U0054>;<U0055>;<U0056>;<U0057>;<U0058>;\
+      <U0059>;<U005A>
+
+digit <U0030>;<U0031>;<U0032>;<U0033>;<U0034>;\
+      <U0035>;<U0036>;<U0037>;<U0038>;<U0039>;\
+      <U2080>;<U2081>;<U2082>;<U2083>;<U2084>;\
+      <U2085>;<U2086>;<U2087>;<U2088>;<U2089>
+
+outdigit <U2080>;<U2081>;<U2082>;<U2083>;<U2084>;\
+         <U2085>;<U2086>;<U2087>;<U2088>;<U2089>
+END LC_CTYPE
+
+LC_NUMERIC
+decimal_point   "<U002E>"
+thousands_sep   "<U002C>"
+grouping        3;3
+END LC_NUMERIC
diff --git a/localedata/tst-digits.c b/localedata/tst-digits.c
new file mode 100644
index 0000000000..372e8acd8c
--- /dev/null
+++ b/localedata/tst-digits.c
@@ -0,0 +1,81 @@
+#include <locale.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+
+#define ZERO  "\xe2\x82\x80"
+#define ONE   "\xe2\x82\x81"
+#define TWO   "\xe2\x82\x82"
+#define THREE "\xe2\x82\x83"
+#define FOUR  "\xe2\x82\x84"
+#define FIVE  "\xe2\x82\x85"
+#define SIX   "\xe2\x82\x86"
+#define SEVEN "\xe2\x82\x87"
+#define EIGHT "\xe2\x82\x88"
+#define NINE  "\xe2\x82\x89"
+
+static struct printf_int_test
+{
+  int n;
+  const char *format;
+  const char *expected;
+} printf_int_tests[] =
+{
+  {       0, "%I'10d", "       " ZERO },
+  {       1, "%I'10d", "       " ONE },
+  {       2, "%I'10d", "       " TWO },
+  {       3, "%I'10d", "       " THREE },
+  {       4, "%I'10d", "       " FOUR },
+  {       5, "%I'10d", "       " FIVE },
+  {       6, "%I'10d", "       " SIX },
+  {       7, "%I'10d", "       " SEVEN },
+  {       8, "%I'10d", "       " EIGHT },
+  {       9, "%I'10d", "       " NINE },
+  {      11, "%I'10d", "    " ONE ONE },
+  {      12, "%I'10d", "    " ONE TWO },
+  {     123, "%I10d",  " " ONE TWO THREE },
+  {     123, "%I'10d", " " ONE TWO THREE },
+  {    1234, "%I10d",  ONE TWO THREE FOUR },
+  {    1234, "%I'10d", ONE "," TWO THREE FOUR },
+  {   12345, "%I'10d", ONE TWO "," THREE FOUR FIVE },
+  {  123456, "%I'10d", ONE TWO THREE "," FOUR FIVE SIX },
+  { 1234567, "%I'10d", ONE "," TWO THREE FOUR "," FIVE SIX SEVEN }
+};
+
+
+
+int
+main (void)
+{
+  int cnt;
+  int printf_failures = 0;
+
+  if (setlocale (LC_ALL, "test7") == NULL)
+    {
+      puts ("cannot set locale `test7'");
+      exit (1);
+    }
+
+  /* First: printf tests.  */
+  for (cnt = 0; cnt < sizeof (printf_int_tests) / sizeof (printf_int_tests[0]);
+       ++cnt)
+    {
+      char buf[100];
+      ssize_t n;
+
+      n = snprintf (buf, sizeof buf, printf_int_tests[cnt].format,
+		    printf_int_tests[cnt].n);
+
+      if (n != strlen (printf_int_tests[cnt].expected)
+	  || strcmp (buf, printf_int_tests[cnt].expected) != 0)
+	{
+	  printf ("%3d: got \"%s\", expected \"%s\"\n",
+		  cnt, buf, printf_int_tests[cnt].expected);
+	  ++printf_failures;
+	}
+    }
+
+  printf ("\n%d failures in printf tests\n", printf_failures);
+
+  return printf_failures != 0;
+}
diff --git a/localedata/tst-locale.sh b/localedata/tst-locale.sh
index 4d503114ee..5aa43e069f 100755
--- a/localedata/tst-locale.sh
+++ b/localedata/tst-locale.sh
@@ -40,6 +40,8 @@ test_locale ()
 	echo "Charmap: \"${charmap}\" Inputfile: \"${input}\"" \
 	     "Outputdir: \"${out}\" failed"
 	exit 1
+    else
+	echo "locale $out generated succesfully"
     fi
 }
 
@@ -49,6 +51,8 @@ test_locale tests/test2.cm tests/test2.def test2
 test_locale tests/test3.cm tests/test3.def test3
 test_locale tests/test4.cm tests/test4.def test4
 test_locale tests/test5.cm tests/test5.def test5 tests/test5.ds
+test_locale tests/test6.cm tests/test6.def test6 tests/test6.ds
+test_locale tests/test7.cm tests/test4.def test7
 
 exit 0
 
diff --git a/stdio-common/Depend b/stdio-common/Depend
new file mode 100644
index 0000000000..f3e1156a4e
--- /dev/null
+++ b/stdio-common/Depend
@@ -0,0 +1 @@
+localedata
diff --git a/stdio-common/_i18n_itoa.c b/stdio-common/_i18n_itoa.c
deleted file mode 100644
index 55a7b28ec2..0000000000
--- a/stdio-common/_i18n_itoa.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/* Internal function for converting integers to string using locale
-   specific digits.
-   Copyright (C) 2000 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-#include <gmp-mparam.h>
-#include <stdlib/gmp.h>
-#include <stdlib/gmp-impl.h>
-#include <stdlib/longlong.h>
-
-#include "_i18n_itoa.h"
-
-
-/* Canonize environment.  For some architectures not all values might
-   be defined in the GMP header files.  */
-#ifndef UMUL_TIME
-# define UMUL_TIME 1
-#endif
-#ifndef UDIV_TIME
-# define UDIV_TIME 3
-#endif
-
-/* Control memory layout.  */
-#ifdef PACK
-# undef PACK
-# define PACK __attribute__ ((packed))
-#else
-# define PACK
-#endif
-
-
-/* Declare local types.  */
-struct base_table_t
-{
-#if (UDIV_TIME > 2 * UMUL_TIME)
-  mp_limb_t base_multiplier;
-#endif
-  char flag;
-  char post_shift;
-#if BITS_PER_MP_LIMB == 32
-  struct
-    {
-      char normalization_steps;
-      char ndigits;
-      mp_limb_t base PACK;
-#if UDIV_TIME > 2 * UMUL_TIME
-      mp_limb_t base_ninv PACK;
-#endif
-    } big;
-#endif
-};
-
-
-/* Variable in other file.  */
-extern const struct base_table_t _itoa_base_table[];
-
-
-char *
-_i18n_itoa (value, buflim)
-     unsigned long long int value;
-     char *buflim;
-{
-  const struct base_table_t *brec = &_itoa_base_table[8];
-
-#if BITS_PER_MP_LIMB == 64
-  mp_limb_t base_multiplier = brec->base_multiplier;
-  if (brec->flag)    while (value != 0)
-      {
-	mp_limb_t quo, rem, x, dummy;
-
-	umul_ppmm (x, dummy, value, base_multiplier);
-	quo = (x + ((value - x) >> 1)) >> (brec->post_shift - 1);
-	rem = value - quo * 10;
-	buflim = outdigit_value (buflim, rem);
-	value = quo;
-      }
-  else
-    while (value != 0)
-      {
-	mp_limb_t quo, rem, x, dummy;
-
-	umul_ppmm (x, dummy, value, base_multiplier);
-	quo = x >> brec->post_shift;
-	rem = value - quo * 10;
-	buflim = outdigit_value (buflim, rem);
-	value = quo;
-      }
-#endif
-#if BITS_PER_MP_LIMB == 32
-  mp_limb_t t[3];
-  int n;
-
-  /* First convert x0 to 1-3 words in base s->big.base.
-     Optimize for frequent cases of 32 bit numbers.  */
-  if ((mp_limb_t) (value >> 32) >= 1)
-    {
-#if UDIV_TIME > 2 * UMUL_TIME || UDIV_NEEDS_NORMALIZATION
-      int big_normalization_steps = brec->big.normalization_steps;
-      mp_limb_t big_base_norm
-	= brec->big.base << big_normalization_steps;
-#endif
-      if ((mp_limb_t) (value >> 32) >= brec->big.base)
-	{
-	  mp_limb_t x1hi, x1lo, r;
-	  /* If you want to optimize this, take advantage of
-	     that the quotient in the first udiv_qrnnd will
-	     always be very small.  It might be faster just to
-	     subtract in a tight loop.  */
-
-#if UDIV_TIME > 2 * UMUL_TIME
-	  mp_limb_t x, xh, xl;
-
-	  if (big_normalization_steps == 0)
-	    xh = 0;
-	  else
-	    xh = (mp_limb_t) (value >> (64 - big_normalization_steps));
-	  xl = (mp_limb_t) (value >> (32 - big_normalization_steps));
-	  udiv_qrnnd_preinv (x1hi, r, xh, xl, big_base_norm,
-			     brec->big.base_ninv);
-
-	  xl = ((mp_limb_t) value) << big_normalization_steps;
-	  udiv_qrnnd_preinv (x1lo, x, r, xl, big_base_norm,
-			     brec->big.base_ninv);
-	  t[2] = x >> big_normalization_steps;
-
-	  if (big_normalization_steps == 0)
-	    xh = x1hi;
-	  else
-	    xh = ((x1hi << big_normalization_steps)
-		  | (x1lo >> (32 - big_normalization_steps)));
-	  xl = x1lo << big_normalization_steps;
-	  udiv_qrnnd_preinv (t[0], x, xh, xl, big_base_norm,
-			     brec->big.base_ninv);
-	  t[1] = x >> big_normalization_steps;
-#elif UDIV_NEEDS_NORMALIZATION
-	  mp_limb_t x, xh, xl;
-
-	  if (big_normalization_steps == 0)
-	    xh = 0;
-	  else
-	    xh = (mp_limb_t) (value >> 64 - big_normalization_steps);
-	  xl = (mp_limb_t) (value >> 32 - big_normalization_steps);
-	  udiv_qrnnd (x1hi, r, xh, xl, big_base_norm);
-
-	  xl = ((mp_limb_t) value) << big_normalization_steps;
-	  udiv_qrnnd (x1lo, x, r, xl, big_base_norm);
-	  t[2] = x >> big_normalization_steps;
-
-	  if (big_normalization_steps == 0)
-	    xh = x1hi;
-	  else
-	    xh = ((x1hi << big_normalization_steps)
-		  | (x1lo >> 32 - big_normalization_steps));
-	  xl = x1lo << big_normalization_steps;
-	  udiv_qrnnd (t[0], x, xh, xl, big_base_norm);
-	  t[1] = x >> big_normalization_steps;
-#else
-	  udiv_qrnnd (x1hi, r, 0, (mp_limb_t) (value >> 32),
-		      brec->big.base);
-	  udiv_qrnnd (x1lo, t[2], r, (mp_limb_t) value, brec->big.base);
-	  udiv_qrnnd (t[0], t[1], x1hi, x1lo, brec->big.base);
-#endif
-	  n = 3;
-	}
-      else
-	{
-#if (UDIV_TIME > 2 * UMUL_TIME)
-	  mp_limb_t x;
-
-	  value <<= brec->big.normalization_steps;
-	  udiv_qrnnd_preinv (t[0], x, (mp_limb_t) (value >> 32),
-			     (mp_limb_t) value, big_base_norm,
-			     brec->big.base_ninv);
-	  t[1] = x >> brec->big.normalization_steps;
-#elif UDIV_NEEDS_NORMALIZATION
-	  mp_limb_t x;
-
-	  value <<= big_normalization_steps;
-	  udiv_qrnnd (t[0], x, (mp_limb_t) (value >> 32),
-		      (mp_limb_t) value, big_base_norm);
-	  t[1] = x >> big_normalization_steps;
-#else
-	  udiv_qrnnd (t[0], t[1], (mp_limb_t) (value >> 32),
-		      (mp_limb_t) value, brec->big.base);
-#endif
-	  n = 2;
-	}
-    }
-  else
-    {
-      t[0] = value;
-      n = 1;
-    }
-
-  /* Convert the 1-3 words in t[], word by word, to ASCII.  */
-  do
-    {
-      mp_limb_t ti = t[--n];
-      int ndig_for_this_limb = 0;
-
-#if UDIV_TIME > 2 * UMUL_TIME
-      mp_limb_t base_multiplier = brec->base_multiplier;
-      if (brec->flag)
-	while (ti != 0)
-	  {
-	    mp_limb_t quo, rem, x, dummy;
-
-	    umul_ppmm (x, dummy, ti, base_multiplier);
-	    quo = (x + ((ti - x) >> 1)) >> (brec->post_shift - 1);
-	    rem = ti - quo * 10;
-	    buflim = outdigit_value (buflim, rem);
-	    ti = quo;
-	    ++ndig_for_this_limb;
-	  }      else
-	while (ti != 0)
-	  {
-	    mp_limb_t quo, rem, x, dummy;
-
-	    umul_ppmm (x, dummy, ti, base_multiplier);
-	    quo = x >> brec->post_shift;
-	    rem = ti - quo * 10;
-	    buflim = outdigit_value (buflim, rem);
-	    ti = quo;
-	    ++ndig_for_this_limb;
-	  }
-#else
-      while (ti != 0)
-	{
-	  mp_limb_t quo, rem;
-
-	  quo = ti / 10;
-	  rem = ti % 10;
-	  buflim = outdigit_value (buflim, rem);
-	  ti = quo;
-	  ++ndig_for_this_limb;
-	}
-#endif
-      /* If this wasn't the most significant word, pad with zeros.  */
-      if (n != 0)
-	while (ndig_for_this_limb < brec->big.ndigits)
-	  {
-	    *--buflim = '0';
-	    ++ndig_for_this_limb;
-	  }
-    }
-  while (n != 0);
-#endif
-
-  return buflim;
-}
diff --git a/stdio-common/_i18n_itoa.h b/stdio-common/_i18n_itoa.h
deleted file mode 100644
index 5662cd91f3..0000000000
--- a/stdio-common/_i18n_itoa.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Internal function for converting integers to string using locale
-   specific digits.
-   Copyright (C) 2000 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-#ifndef _I18N_ITOA_H
-#define _I18N_ITOA_H
-#include <sys/cdefs.h>
-
-#include "../locale/outdigits.h"
-
-
-extern char *_i18n_itoa (unsigned long long int value, char *buflim);
-
-static inline char *
-_i18n_itoa_word (unsigned long int value, char *buflim)
-{
-  do
-    buflim = outdigit_value (buflim, value % 10);
-  while ((value /= 10) != 0);					      \
-
-  return buflim;
-}
-
-#endif	/* _i18n_itoa.h */
diff --git a/stdio-common/_i18n_itowa.c b/stdio-common/_i18n_itowa.c
deleted file mode 100644
index 357f8a383b..0000000000
--- a/stdio-common/_i18n_itowa.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/* Internal function for converting integers to string using locale
-   specific digits.
-   Copyright (C) 2000 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-#include <gmp-mparam.h>
-#include <stdlib/gmp.h>
-#include <stdlib/gmp-impl.h>
-#include <stdlib/longlong.h>
-
-#include "_i18n_itowa.h"
-
-
-/* Canonize environment.  For some architectures not all values might
-   be defined in the GMP header files.  */
-#ifndef UMUL_TIME
-# define UMUL_TIME 1
-#endif
-#ifndef UDIV_TIME
-# define UDIV_TIME 3
-#endif
-
-/* Control memory layout.  */
-#ifdef PACK
-# undef PACK
-# define PACK __attribute__ ((packed))
-#else
-# define PACK
-#endif
-
-
-/* Declare local types.  */
-struct base_table_t
-{
-#if (UDIV_TIME > 2 * UMUL_TIME)
-  mp_limb_t base_multiplier;
-#endif
-  char flag;
-  char post_shift;
-#if BITS_PER_MP_LIMB == 32
-  struct
-    {
-      char normalization_steps;
-      char ndigits;
-      mp_limb_t base PACK;
-#if UDIV_TIME > 2 * UMUL_TIME
-      mp_limb_t base_ninv PACK;
-#endif
-    } big;
-#endif
-};
-
-
-/* Variable in other file.  */
-extern const struct base_table_t _itoa_base_table[];
-
-
-wchar_t *
-_i18n_itowa (value, buflim)
-     unsigned long long int value;
-     wchar_t *buflim;
-{
-  const struct base_table_t *brec = &_itoa_base_table[8];
-
-#if BITS_PER_MP_LIMB == 64
-  mp_limb_t base_multiplier = brec->base_multiplier;
-  if (brec->flag)    while (value != 0)
-      {
-	mp_limb_t quo, rem, x, dummy;
-
-	umul_ppmm (x, dummy, value, base_multiplier);
-	quo = (x + ((value - x) >> 1)) >> (brec->post_shift - 1);
-	rem = value - quo * 10;
-	*--buflim = outdigitwc_value (rem);
-	value = quo;
-      }
-  else
-    while (value != 0)
-      {
-	mp_limb_t quo, rem, x, dummy;
-
-	umul_ppmm (x, dummy, value, base_multiplier);
-	quo = x >> brec->post_shift;
-	rem = value - quo * 10;
-	*--buflim = outdigitwc_value (rem);
-	value = quo;
-      }
-#endif
-#if BITS_PER_MP_LIMB == 32
-  mp_limb_t t[3];
-  int n;
-
-  /* First convert x0 to 1-3 words in base s->big.base.
-     Optimize for frequent cases of 32 bit numbers.  */
-  if ((mp_limb_t) (value >> 32) >= 1)
-    {
-#if UDIV_TIME > 2 * UMUL_TIME || UDIV_NEEDS_NORMALIZATION
-      int big_normalization_steps = brec->big.normalization_steps;
-      mp_limb_t big_base_norm
-	= brec->big.base << big_normalization_steps;
-#endif
-      if ((mp_limb_t) (value >> 32) >= brec->big.base)
-	{
-	  mp_limb_t x1hi, x1lo, r;
-	  /* If you want to optimize this, take advantage of
-	     that the quotient in the first udiv_qrnnd will
-	     always be very small.  It might be faster just to
-	     subtract in a tight loop.  */
-
-#if UDIV_TIME > 2 * UMUL_TIME
-	  mp_limb_t x, xh, xl;
-
-	  if (big_normalization_steps == 0)
-	    xh = 0;
-	  else
-	    xh = (mp_limb_t) (value >> (64 - big_normalization_steps));
-	  xl = (mp_limb_t) (value >> (32 - big_normalization_steps));
-	  udiv_qrnnd_preinv (x1hi, r, xh, xl, big_base_norm,
-			     brec->big.base_ninv);
-
-	  xl = ((mp_limb_t) value) << big_normalization_steps;
-	  udiv_qrnnd_preinv (x1lo, x, r, xl, big_base_norm,
-			     brec->big.base_ninv);
-	  t[2] = x >> big_normalization_steps;
-
-	  if (big_normalization_steps == 0)
-	    xh = x1hi;
-	  else
-	    xh = ((x1hi << big_normalization_steps)
-		  | (x1lo >> (32 - big_normalization_steps)));
-	  xl = x1lo << big_normalization_steps;
-	  udiv_qrnnd_preinv (t[0], x, xh, xl, big_base_norm,
-			     brec->big.base_ninv);
-	  t[1] = x >> big_normalization_steps;
-#elif UDIV_NEEDS_NORMALIZATION
-	  mp_limb_t x, xh, xl;
-
-	  if (big_normalization_steps == 0)
-	    xh = 0;
-	  else
-	    xh = (mp_limb_t) (value >> 64 - big_normalization_steps);
-	  xl = (mp_limb_t) (value >> 32 - big_normalization_steps);
-	  udiv_qrnnd (x1hi, r, xh, xl, big_base_norm);
-
-	  xl = ((mp_limb_t) value) << big_normalization_steps;
-	  udiv_qrnnd (x1lo, x, r, xl, big_base_norm);
-	  t[2] = x >> big_normalization_steps;
-
-	  if (big_normalization_steps == 0)
-	    xh = x1hi;
-	  else
-	    xh = ((x1hi << big_normalization_steps)
-		  | (x1lo >> 32 - big_normalization_steps));
-	  xl = x1lo << big_normalization_steps;
-	  udiv_qrnnd (t[0], x, xh, xl, big_base_norm);
-	  t[1] = x >> big_normalization_steps;
-#else
-	  udiv_qrnnd (x1hi, r, 0, (mp_limb_t) (value >> 32),
-		      brec->big.base);
-	  udiv_qrnnd (x1lo, t[2], r, (mp_limb_t) value, brec->big.base);
-	  udiv_qrnnd (t[0], t[1], x1hi, x1lo, brec->big.base);
-#endif
-	  n = 3;
-	}
-      else
-	{
-#if (UDIV_TIME > 2 * UMUL_TIME)
-	  mp_limb_t x;
-
-	  value <<= brec->big.normalization_steps;
-	  udiv_qrnnd_preinv (t[0], x, (mp_limb_t) (value >> 32),
-			     (mp_limb_t) value, big_base_norm,
-			     brec->big.base_ninv);
-	  t[1] = x >> brec->big.normalization_steps;
-#elif UDIV_NEEDS_NORMALIZATION
-	  mp_limb_t x;
-
-	  value <<= big_normalization_steps;
-	  udiv_qrnnd (t[0], x, (mp_limb_t) (value >> 32),
-		      (mp_limb_t) value, big_base_norm);
-	  t[1] = x >> big_normalization_steps;
-#else
-	  udiv_qrnnd (t[0], t[1], (mp_limb_t) (value >> 32),
-		      (mp_limb_t) value, brec->big.base);
-#endif
-	  n = 2;
-	}
-    }
-  else
-    {
-      t[0] = value;
-      n = 1;
-    }
-
-  /* Convert the 1-3 words in t[], word by word, to ASCII.  */
-  do
-    {
-      mp_limb_t ti = t[--n];
-      int ndig_for_this_limb = 0;
-
-#if UDIV_TIME > 2 * UMUL_TIME
-      mp_limb_t base_multiplier = brec->base_multiplier;
-      if (brec->flag)
-	while (ti != 0)
-	  {
-	    mp_limb_t quo, rem, x, dummy;
-
-	    umul_ppmm (x, dummy, ti, base_multiplier);
-	    quo = (x + ((ti - x) >> 1)) >> (brec->post_shift - 1);
-	    rem = ti - quo * 10;
-	    *--buflim = outdigitwc_value (rem);
-	    ti = quo;
-	    ++ndig_for_this_limb;
-	  }
-      else
-	while (ti != 0)
-	  {
-	    mp_limb_t quo, rem, x, dummy;
-
-	    umul_ppmm (x, dummy, ti, base_multiplier);
-	    quo = x >> brec->post_shift;
-	    rem = ti - quo * 10;
-	    *--buflim = outdigitwc_value (rem);
-	    ti = quo;
-	    ++ndig_for_this_limb;
-	  }
-#else
-      while (ti != 0)
-	{
-	  mp_limb_t quo, rem;
-
-	  quo = ti / 10;
-	  rem = ti % 10;
-	  *--buflim = outdigitwc_value (rem);
-	  ti = quo;
-	  ++ndig_for_this_limb;
-	}
-#endif
-      /* If this wasn't the most significant word, pad with zeros.  */
-      if (n != 0)
-	while (ndig_for_this_limb < brec->big.ndigits)
-	  {
-	    *--buflim = '0';
-	    ++ndig_for_this_limb;
-	  }
-    }
-  while (n != 0);
-#endif
-
-  return buflim;
-}
diff --git a/stdio-common/_i18n_itowa.h b/stdio-common/_i18n_number.h
index f4b091e5f6..d911cf7510 100644
--- a/stdio-common/_i18n_itowa.h
+++ b/stdio-common/_i18n_number.h
@@ -1,8 +1,6 @@
-/* Internal function for converting integers to string using locale
-   specific digits.
-   Copyright (C) 2000 Free Software Foundation, Inc.
+/* Copyright (C) 2000 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
+   Contributed by Ulrich Drepper <drepper@gnu.org>, 2000.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public License as
@@ -19,23 +17,33 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#ifndef _I18N_ITOWA_H
-#define _I18N_ITOWA_H
-#include <sys/cdefs.h>
-
+#include "../locale/outdigits.h"
 #include "../locale/outdigitswc.h"
 
-
-extern wchar_t *_i18n_itowa (unsigned long long int value, wchar_t *buflim);
-
-static inline wchar_t *
-_i18n_itowa_word (unsigned long int value, wchar_t *buflim)
+static CHAR_T *
+_i18n_number_rewrite (CHAR_T *w, CHAR_T *rear_ptr)
 {
-  do
-    *--buflim = outdigitwc_value (value % 10);
-  while ((value /= 10) != 0);					      \
-
-  return buflim;
+  CHAR_T *src, *s;
+
+  /* Copy existing string so that nothing gets overwritten.  */
+  src = (CHAR_T *) alloca ((rear_ptr - w) * sizeof (CHAR_T));
+  s = (CHAR_T *) __mempcpy (src, w,
+			    (rear_ptr - w) * sizeof (CHAR_T));
+  w = rear_ptr;
+
+  /* Process all characters in the string.  */
+  while (--s >= src)
+    {
+      if (*s >= '0' && *s <= '9')
+	{
+	  if (sizeof (CHAR_T) == 1)
+	    w = (CHAR_T *) outdigit_value ((char *) w, *s - '0');
+	  else
+	    *--w = (CHAR_T) outdigitwc_value (*s - '0');
+	}
+      else
+	*--w = *s;
+    }
+
+  return w;
 }
-
-#endif	/* _i18n_itoa.h */
diff --git a/stdio-common/bug13.c b/stdio-common/bug13.c
index 17b7ff9825..1eca8185ca 100644
--- a/stdio-common/bug13.c
+++ b/stdio-common/bug13.c
@@ -11,7 +11,7 @@ main (void)
 #define TEST(nr, result, format, args...) \
   if (sprintf (buf, format, ## args) != result)				      \
     {									      \
-      printf ("test %d failed\n", nr);					      \
+      printf ("test %d failed (\"%s\",  %d)\n", nr, buf, result);	      \
       res = 1;								      \
     }
 
diff --git a/stdio-common/printf-parse.h b/stdio-common/printf-parse.h
index e9772ef666..45bcc3a9bb 100644
--- a/stdio-common/printf-parse.h
+++ b/stdio-common/printf-parse.h
@@ -172,42 +172,48 @@ parse_one_spec (const UCHAR_T *format, size_t posn, struct printf_spec *spec,
     }
 
   /* Check for spec modifiers.  */
-  while (*format == L_(' ') || *format == L_('+') || *format == L_('-') ||
-	 *format == L_('#') || *format == L_('0') || *format == L_('\''))
-    switch (*format++)
-      {
-      case L_(' '):
-	/* Output a space in place of a sign, when there is no sign.  */
-	spec->info.space = 1;
-	break;
-      case L_('+'):
-	/* Always output + or - for numbers.  */
-	spec->info.showsign = 1;
-	break;
-      case L_('-'):
-	/* Left-justify things.  */
-	spec->info.left = 1;
-	break;
-      case L_('#'):
-	/* Use the "alternate form":
-	   Hex has 0x or 0X, FP always has a decimal point.  */
-	spec->info.alt = 1;
-	break;
-      case L_('0'):
-	/* Pad with 0s.  */
-	spec->info.pad = '0';
-	break;
-      case L_('\''):
-	/* Show grouping in numbers if the locale information
-	   indicates any.  */
-	spec->info.group = 1;
-	break;
-      case L_('I'):
-	/* Use the internationalized form of the output.  Currently
-	   means to use the `outdigits' of the current locale.  */
-	spec->info.i18n = 1;
-	break;
-      }
+  do
+    {
+      switch (*format)
+	{
+	case L_(' '):
+	  /* Output a space in place of a sign, when there is no sign.  */
+	  spec->info.space = 1;
+	  continue;
+	case L_('+'):
+	  /* Always output + or - for numbers.  */
+	  spec->info.showsign = 1;
+	  continue;
+	case L_('-'):
+	  /* Left-justify things.  */
+	  spec->info.left = 1;
+	  continue;
+	case L_('#'):
+	  /* Use the "alternate form":
+	     Hex has 0x or 0X, FP always has a decimal point.  */
+	  spec->info.alt = 1;
+	  continue;
+	case L_('0'):
+	  /* Pad with 0s.  */
+	  spec->info.pad = '0';
+	  continue;
+	case L_('\''):
+	  /* Show grouping in numbers if the locale information
+	     indicates any.  */
+	  spec->info.group = 1;
+	  continue;
+	case L_('I'):
+	  /* Use the internationalized form of the output.  Currently
+	     means to use the `outdigits' of the current locale.  */
+	  spec->info.i18n = 1;
+	  continue;
+	default:
+	  break;
+	}
+      break;
+    }
+  while (*++format);
+
   if (spec->info.left)
     spec->info.pad = ' ';
 
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index 2a077b480a..91179564fd 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -22,12 +22,12 @@
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <string.h>
 #include <errno.h>
 #include <wchar.h>
 #include <bits/libc-lock.h>
 #include <sys/param.h>
 #include "_itoa.h"
-#include "_i18n_itoa.h"
 #include <locale/localeinfo.h>
 
 /* This code is shared between the standard stdio implementation found
@@ -70,7 +70,7 @@
 #  define UCHAR_T	unsigned char
 #  define INT_T		int
 #  define L_(Str)	Str
-#  define ISDIGIT(Ch)	isdigit (Ch)
+#  define ISDIGIT(Ch)	((unsigned int) ((Ch) - '0') < 10)
 
 #  define PUT(F, S, N)	_IO_sputn ((F), (S), (N))
 #  define PAD(Padchar) \
@@ -80,16 +80,15 @@
 #  define ORIENT	if (s->_vtable_offset == 0 && _IO_fwide (s, -1) != -1)\
 			  return -1
 # else
-# include "_itowa.h"
-# include "_i18n_itowa.h"
-
 #  define vfprintf	_IO_vfwprintf
 #  define CHAR_T	wchar_t
 /* This is a hack!!!  There should be a type uwchar_t.  */
 #  define UCHAR_T	unsigned int /* uwchar_t */
 #  define INT_T		wint_t
 #  define L_(Str)	L##Str
-#  define ISDIGIT(Ch)	iswdigit (Ch)
+#  define ISDIGIT(Ch)	((unsigned int) ((Ch) - L'0') < 10)
+
+#  include "_itowa.h"
 
 #  define PUT(F, S, N)	_IO_sputn ((F), (S), (N))
 #  define PAD(Padchar) \
@@ -100,11 +99,11 @@
 
 #  define _itoa(Val, Buf, Base, Case) _itowa (Val, Buf, Base, Case)
 #  define _itoa_word(Val, Buf, Base, Case) _itowa_word (Val, Buf, Base, Case)
-#  define _i18n_itoa(Val, Buf) _i18n_itowa (Val, Buf)
-#  define _i18n_itoa_word(Val, Buf) _i18n_itowa_word (Val, Buf)
 #  undef EOF
 #  define EOF WEOF
 # endif
+
+# include "_i18n_number.h"
 #else /* ! USE_IN_LIBIO */
 /* This code is for use in the GNU C library.  */
 # include <stdio.h>
@@ -638,20 +637,19 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
 	    {								      \
 	      string = workend;						      \
 	      if (base == 8 && alt)					      \
-		*string-- = L_('0');					      \
+		*--string = L_('0');					      \
 	    }								      \
 	  else								      \
 	    {								      \
 	      /* Put the number in WORK.  */				      \
-	      if (use_outdigits && base == 10)				      \
-	        string = _i18n_itoa (number.longlong, workend + 1);	      \
-	      else							      \
-	        string = _itoa (number.longlong, workend + 1, base,	      \
-			        spec == L_('X'));			      \
-	      string -= 1;						      \
+	      string = _itoa (number.longlong, workend, base,		      \
+			      spec == L_('X'));				      \
 	      if (group && grouping)					      \
 		string = group_number (string, workend, grouping,	      \
 				       thousands_sep);			      \
+									      \
+	      if (use_outdigits && base == 10)				      \
+		string = _i18n_number_rewrite (string, workend);	      \
 	    }								      \
 	  /* Simplify further test for num != 0.  */			      \
 	  number.word = number.longlong != 0;				      \
@@ -695,26 +693,25 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
 	    {								      \
 	      string = workend;						      \
 	      if (base == 8 && alt)					      \
-		*string-- = L_('0');					      \
+		*--string = L_('0');					      \
 	    }								      \
 	  else								      \
 	    {								      \
 	      /* Put the number in WORK.  */				      \
-	      if (use_outdigits && base == 10)				      \
-	        string = _i18n_itoa_word (number.word, workend + 1);	      \
-	      else							      \
-	        string = _itoa_word (number.word, workend + 1, base,	      \
-				     spec == L_('X'));			      \
-	      string -= 1;						      \
+	      string = _itoa_word (number.word, workend, base,		      \
+				   spec == L_('X'));			      \
 	      if (group && grouping)					      \
 		string = group_number (string, workend, grouping,	      \
 				       thousands_sep);			      \
+									      \
+	      if (use_outdigits && base == 10)				      \
+		string = _i18n_number_rewrite (string, workend);	      \
 	    }								      \
 	}								      \
 									      \
       if (prec <= workend - string && number.word != 0 && alt && base == 8)   \
 	/* Add octal marker.  */					      \
-	*string-- = L_('0');						      \
+	*--string = L_('0');						      \
 									      \
       prec = MAX (0, prec - (workend - string));			      \
 									      \
@@ -751,7 +748,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
 	  width += prec;						      \
 	  PAD (L_('0'));						      \
 									      \
-	  outstring (string + 1, workend - string);			      \
+	  outstring (string, workend - string);				      \
 									      \
 	  break;							      \
 	}								      \
@@ -790,7 +787,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
 	      width = temp;						      \
 	    }								      \
 									      \
-	  outstring (string + 1, workend - string);			      \
+	  outstring (string, workend - string);				      \
 									      \
 	  PAD (L_(' '));						      \
 	  break;							      \
@@ -1325,7 +1322,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
       UCHAR_T pad = L_(' ');/* Padding character.  */
       CHAR_T spec;
 
-      workend = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T) - 1];
+      workend = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)];
 
       /* Get current character in format string.  */
       JUMP (*++f, step0_jumps);
@@ -1410,7 +1407,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
 	  /* We have to use a special buffer.  The "32" is just a safe
 	     bet for all the output which is not counted in the width.  */
 	  workend = ((CHAR_T *) alloca ((width + 32) * sizeof (CHAR_T))
-		     + (width + 31));
+		     + (width + 32));
       }
       JUMP (*f, step1_jumps);
 
@@ -1422,7 +1419,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
 	/* We have to use a special buffer.  The "32" is just a safe
 	   bet for all the output which is not counted in the width.  */
 	workend = ((CHAR_T *) alloca ((width + 32) * sizeof (CHAR_T))
-		   + (width + 31));
+		   + (width + 32));
       if (*f == L_('$'))
 	/* Oh, oh.  The argument comes from a positional parameter.  */
 	goto do_positional;
@@ -1451,7 +1448,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap)
 	prec = 0;
       if (prec > width
 	  && prec + 32 > sizeof (work_buffer) / sizeof (work_buffer[0]))
-	workend = alloca (spec + 32) + (spec + 31);
+	workend = alloca (spec + 32) + (spec + 32);
       JUMP (*f, step2_jumps);
 
       /* Process 'h' modifier.  There might another 'h' following.  */
@@ -1749,7 +1746,7 @@ do_positional:
 	if (MAX (prec, width) + 32 > sizeof (work_buffer) / sizeof (CHAR_T))
 	  workend = ((CHAR_T *) alloca ((MAX (prec, width) + 32)
 					* sizeof (CHAR_T))
-		     + (MAX (prec, width) + 31));
+		     + (MAX (prec, width) + 32));
 
 	/* Process format specifiers.  */
 	while (1)
@@ -1826,7 +1823,7 @@ printf_unknown (FILE *s, const struct printf_info *info,
   int done = 0;
   CHAR_T work_buffer[MAX (info->width, info->spec) + 32];
   CHAR_T *const workend
-    = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T) - 1];
+    = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)];
   register CHAR_T *w;
 
   outchar (L_('%'));
@@ -1848,16 +1845,16 @@ printf_unknown (FILE *s, const struct printf_info *info,
 
   if (info->width != 0)
     {
-      w = _itoa_word (info->width, workend + 1, 10, 0);
-      while (w <= workend)
+      w = _itoa_word (info->width, workend, 10, 0);
+      while (w < workend)
 	outchar (*w++);
     }
 
   if (info->prec != -1)
     {
       outchar (L_('.'));
-      w = _itoa_word (info->prec, workend + 1, 10, 0);
-      while (w <= workend)
+      w = _itoa_word (info->prec, workend, 10, 0);
+      while (w < workend)
 	outchar (*w++);
     }
 
@@ -1896,24 +1893,24 @@ group_number (CHAR_T *w, CHAR_T *rear_ptr, const char *grouping,
 
   /* Copy existing string so that nothing gets overwritten.  */
   src = (CHAR_T *) alloca ((rear_ptr - w) * sizeof (CHAR_T));
-  s = (CHAR_T *) __mempcpy (src, w + 1,
-			    (rear_ptr - w) * sizeof (CHAR_T)) - 1;
+  s = (CHAR_T *) __mempcpy (src, w,
+			    (rear_ptr - w) * sizeof (CHAR_T));
   w = rear_ptr;
 
   /* Process all characters in the string.  */
-  while (s >= src)
+  while (s > src)
     {
-      *w-- = *s--;
+      *--w = *--s;
 
-      if (--len == 0 && s >= src)
+      if (--len == 0 && s > src)
 	{
 	  /* A new group begins.  */
 #ifdef COMPILE_WPRINTF
-	  *w-- = thousands_sep;
+	  *--w = thousands_sep;
 #else
 	  int cnt = tlen;
 	  do
-	    *w-- = thousands_sep[--cnt];
+	    *--w = thousands_sep[--cnt];
 	  while (cnt > 0);
 #endif
 
@@ -1930,8 +1927,8 @@ group_number (CHAR_T *w, CHAR_T *rear_ptr, const char *grouping,
 	      /* No further grouping to be done.
 		 Copy the rest of the number.  */
 	      do
-		*w-- = *s--;
-	      while (s >= src);
+		*--w = *--s;
+	      while (s > src);
 	      break;
 	    }
 	}