summary refs log tree commit diff
path: root/stdio-common
diff options
context:
space:
mode:
Diffstat (limited to 'stdio-common')
-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
8 files changed, 113 insertions, 675 deletions
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;
 	    }
 	}