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/Makefile47
-rw-r--r--stdio-common/_itoa.c418
-rw-r--r--stdio-common/_itoa.h32
-rw-r--r--stdio-common/asprintf.c42
-rw-r--r--stdio-common/bug1.c28
-rw-r--r--stdio-common/bug1.input1
-rw-r--r--stdio-common/bug2.c12
-rw-r--r--stdio-common/bug3.c52
-rw-r--r--stdio-common/bug4.c50
-rw-r--r--stdio-common/bug5.c60
-rw-r--r--stdio-common/bug6.c27
-rw-r--r--stdio-common/bug6.input1
-rw-r--r--stdio-common/bug7.c53
-rw-r--r--stdio-common/dprintf.c41
-rw-r--r--stdio-common/errnobug.c60
-rw-r--r--stdio-common/fprintf.c38
-rw-r--r--stdio-common/fscanf.c38
-rw-r--r--stdio-common/getline.c33
-rw-r--r--stdio-common/getw.c33
-rw-r--r--stdio-common/perror.c42
-rw-r--r--stdio-common/printf-parse.h388
-rw-r--r--stdio-common/printf-prs.c72
-rw-r--r--stdio-common/printf.c40
-rw-r--r--stdio-common/printf.h124
-rw-r--r--stdio-common/printf_fp.c990
-rw-r--r--stdio-common/psignal.c49
-rw-r--r--stdio-common/putw.c31
-rw-r--r--stdio-common/reg-printf.c47
-rw-r--r--stdio-common/scanf.c40
-rw-r--r--stdio-common/snprintf.c43
-rw-r--r--stdio-common/sprintf.c41
-rw-r--r--stdio-common/sscanf.c41
-rw-r--r--stdio-common/tempnam.c50
-rw-r--r--stdio-common/temptest.c31
-rw-r--r--stdio-common/test-fseek.c67
-rw-r--r--stdio-common/test-fwrite.c68
-rw-r--r--stdio-common/test-popen.c67
-rw-r--r--stdio-common/test_rdwr.c130
-rw-r--r--stdio-common/tmpfile.c43
-rw-r--r--stdio-common/tmpnam.c42
-rw-r--r--stdio-common/tst-fileno.c37
-rw-r--r--stdio-common/tst-printf.c298
-rw-r--r--stdio-common/tstgetln.c46
-rw-r--r--stdio-common/tstgetln.input3
-rw-r--r--stdio-common/tstscanf.c100
-rw-r--r--stdio-common/tstscanf.input7
-rw-r--r--stdio-common/vasprintf.c86
-rw-r--r--stdio-common/vdprintf.c51
-rw-r--r--stdio-common/vfprintf.c858
-rw-r--r--stdio-common/vfscanf.c624
-rw-r--r--stdio-common/vprintf.c37
-rw-r--r--stdio-common/vscanf.c32
-rw-r--r--stdio-common/vsnprintf.c56
-rw-r--r--stdio-common/vsprintf.c50
-rw-r--r--stdio-common/vsscanf.c58
-rw-r--r--stdio-common/xbug.c63
56 files changed, 5918 insertions, 0 deletions
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
new file mode 100644
index 0000000000..6ca6c7d1d3
--- /dev/null
+++ b/stdio-common/Makefile
@@ -0,0 +1,47 @@
+# Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# 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., 675 Mass Ave,
+# Cambridge, MA 02139, USA.
+
+#
+#	Specific makefile for stdio-common.
+#
+subdir	:= stdio-common
+
+headers	:= stdio_lim.h printf.h
+
+routines	:=							      \
+	ctermid cuserid							      \
+	vfprintf vprintf printf_fp reg-printf printf-prs _itoa		      \
+	vsnprintf vsprintf vasprintf	      				      \
+	fprintf printf snprintf sprintf asprintf			      \
+	dprintf vdprintf						      \
+	vfscanf vscanf vsscanf						      \
+	fscanf scanf sscanf						      \
+	perror psignal							      \
+	tmpfile tmpnam tempnam tempname					      \
+	getline getw putw						      \
+	remove rename
+aux	:= errlist siglist
+distribute := _itoa.h printf-parse.h
+
+tests := tst-printf tstscanf test_rdwr test-popen tstgetln test-fseek \
+	 temptest tst-fileno test-fwrite \
+	 xbug errnobug \
+	 bug1 bug2 bug3 bug4 bug5 bug6 bug7
+
+
+include ../Rules
diff --git a/stdio-common/_itoa.c b/stdio-common/_itoa.c
new file mode 100644
index 0000000000..caa8179624
--- /dev/null
+++ b/stdio-common/_itoa.c
@@ -0,0 +1,418 @@
+/* Internal function for converting integers to ASCII.
+Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Torbjorn Granlund <tege@matematik.su.se>
+and Ulrich Drepper <drepper@gnu.ai.mit.edu>.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <gmp-mparam.h>
+#include "../stdlib/gmp.h"
+#include "../stdlib/gmp-impl.h"
+#include "../stdlib/longlong.h"
+
+#include "_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 1
+#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 base_multiplier;
+#endif
+  char flag;
+  char post_shift;
+#if BITS_PER_MP_LIMB == 32
+  struct
+    {
+      char normalization_steps;
+      char ndigits;
+      mp_limb base PACK;
+#if UDIV_TIME > 2 * UMUL_TIME
+      mp_limb base_ninv PACK;
+#endif
+    } big;
+#endif
+};
+
+/* To reduce the memory needed we include some fields of the tables
+   only confitionally.  */
+#if BITS_PER_MP_LIMB == 32
+# if UDIV_TIME > 2 * UMUL_TIME
+#  define SEL1(X) X,
+#  define SEL2(X) ,X
+# else
+#  define SEL1(X)
+#  define SEL2(X)
+# endif
+#endif
+
+
+/* Local variables.  */
+static const struct base_table_t base_table[] =
+{
+#if BITS_PER_MP_LIMB == 64
+  /*  2 */ {0ul, 1, 1},
+  /*  3 */ {0xaaaaaaaaaaaaaaabul, 0, 1},
+  /*  4 */ {0ul, 1, 2},
+  /*  5 */ {0xcccccccccccccccdul, 0, 2},
+  /*  6 */ {0xaaaaaaaaaaaaaaabul, 0, 2},
+  /*  7 */ {0x2492492492492493ul, 1, 3},
+  /*  8 */ {0ul, 1, 3},
+  /*  9 */ {0xe38e38e38e38e38ful, 0, 3},
+  /* 10 */ {0xcccccccccccccccdul, 0, 3},
+  /* 11 */ {0x2e8ba2e8ba2e8ba3ul, 0, 1},
+  /* 12 */ {0xaaaaaaaaaaaaaaabul, 0, 3},
+  /* 13 */ {0x4ec4ec4ec4ec4ec5ul, 0, 2},
+  /* 14 */ {0x2492492492492493ul, 1, 4},
+  /* 15 */ {0x8888888888888889ul, 0, 3},
+  /* 16 */ {0ul, 1, 4},
+  /* 17 */ {0xf0f0f0f0f0f0f0f1ul, 0, 4},
+  /* 18 */ {0xe38e38e38e38e38ful, 0, 4},
+  /* 19 */ {0xd79435e50d79435ful, 0, 4},
+  /* 20 */ {0xcccccccccccccccdul, 0, 4},
+  /* 21 */ {0x8618618618618619ul, 1, 5},
+  /* 22 */ {0x2e8ba2e8ba2e8ba3ul, 0, 2},
+  /* 23 */ {0x642c8590b21642c9ul, 1, 5},
+  /* 24 */ {0xaaaaaaaaaaaaaaabul, 0, 4},
+  /* 25 */ {0x47ae147ae147ae15ul, 1, 5},
+  /* 26 */ {0x4ec4ec4ec4ec4ec5ul, 0, 3},
+  /* 27 */ {0x97b425ed097b425ful, 0, 4},
+  /* 28 */ {0x2492492492492493ul, 1, 5},
+  /* 29 */ {0x1a7b9611a7b9611bul, 1, 5},
+  /* 30 */ {0x8888888888888889ul, 0, 4},
+  /* 31 */ {0x0842108421084211ul, 1, 5},
+  /* 32 */ {0ul, 1, 5},
+  /* 33 */ {0x0f83e0f83e0f83e1ul, 0, 1},
+  /* 34 */ {0xf0f0f0f0f0f0f0f1ul, 0, 5},
+  /* 35 */ {0xea0ea0ea0ea0ea0ful, 0, 5},
+  /* 36 */ {0xe38e38e38e38e38ful, 0, 5}
+#endif
+#if BITS_PER_MP_LIMB == 32
+  /*  2 */ {SEL1(0ul) 1, 1, {0, 31, 0x80000000ul SEL2(0xfffffffful)}},
+  /*  3 */ {SEL1(0xaaaaaaabul) 0, 1, {0, 20, 0xcfd41b91ul SEL2(0x3b563c24ul)}},
+  /*  4 */ {SEL1(0ul) 1, 2, {1, 15, 0x40000000ul SEL2(0xfffffffful)}},
+  /*  5 */ {SEL1(0xcccccccdul) 0, 2, {1, 13, 0x48c27395ul SEL2(0xc25c2684ul)}},
+  /*  6 */ {SEL1(0xaaaaaaabul) 0, 2, {0, 12, 0x81bf1000ul SEL2(0xf91bd1b6ul)}},
+  /*  7 */ {SEL1(0x24924925ul) 1, 3, {1, 11, 0x75db9c97ul SEL2(0x1607a2cbul)}},
+  /*  8 */ {SEL1(0ul) 1, 3, {1, 10, 0x40000000ul SEL2(0xfffffffful)}},
+  /*  9 */ {SEL1(0x38e38e39ul) 0, 1, {0, 10, 0xcfd41b91ul SEL2(0x3b563c24ul)}},
+  /* 10 */ {SEL1(0xcccccccdul) 0, 3, {2, 9, 0x3b9aca00ul SEL2(0x12e0be82ul)}},
+  /* 11 */ {SEL1(0xba2e8ba3ul) 0, 3, {0, 9, 0x8c8b6d2bul SEL2(0xd24cde04ul)}},
+  /* 12 */ {SEL1(0xaaaaaaabul) 0, 3, {3, 8, 0x19a10000ul SEL2(0x3fa39ab5ul)}},
+  /* 13 */ {SEL1(0x4ec4ec4ful) 0, 2, {2, 8, 0x309f1021ul SEL2(0x50f8ac5ful)}},
+  /* 14 */ {SEL1(0x24924925ul) 1, 4, {1, 8, 0x57f6c100ul SEL2(0x74843b1eul)}},
+  /* 15 */ {SEL1(0x88888889ul) 0, 3, {0, 8, 0x98c29b81ul SEL2(0xad0326c2ul)}},
+  /* 16 */ {SEL1(0ul) 1, 4, {3, 7, 0x10000000ul SEL2(0xfffffffful)}},
+  /* 17 */ {SEL1(0xf0f0f0f1ul) 0, 4, {3, 7, 0x18754571ul SEL2(0x4ef0b6bdul)}},
+  /* 18 */ {SEL1(0x38e38e39ul) 0, 2, {2, 7, 0x247dbc80ul SEL2(0xc0fc48a1ul)}},
+  /* 19 */ {SEL1(0xaf286bcbul) 1, 5, {2, 7, 0x3547667bul SEL2(0x33838942ul)}},
+  /* 20 */ {SEL1(0xcccccccdul) 0, 4, {1, 7, 0x4c4b4000ul SEL2(0xad7f29abul)}},
+  /* 21 */ {SEL1(0x86186187ul) 1, 5, {1, 7, 0x6b5a6e1dul SEL2(0x313c3d15ul)}},
+  /* 22 */ {SEL1(0xba2e8ba3ul) 0, 4, {0, 7, 0x94ace180ul SEL2(0xb8cca9e0ul)}},
+  /* 23 */ {SEL1(0xb21642c9ul) 0, 4, {0, 7, 0xcaf18367ul SEL2(0x42ed6de9ul)}},
+  /* 24 */ {SEL1(0xaaaaaaabul) 0, 4, {4, 6, 0x0b640000ul SEL2(0x67980e0bul)}},
+  /* 25 */ {SEL1(0x51eb851ful) 0, 3, {4, 6, 0x0e8d4a51ul SEL2(0x19799812ul)}},
+  /* 26 */ {SEL1(0x4ec4ec4ful) 0, 3, {3, 6, 0x1269ae40ul SEL2(0xbce85396ul)}},
+  /* 27 */ {SEL1(0x2f684bdbul) 1, 5, {3, 6, 0x17179149ul SEL2(0x62c103a9ul)}},
+  /* 28 */ {SEL1(0x24924925ul) 1, 5, {3, 6, 0x1cb91000ul SEL2(0x1d353d43ul)}},
+  /* 29 */ {SEL1(0x8d3dcb09ul) 0, 4, {2, 6, 0x23744899ul SEL2(0xce1deceaul)}},
+  /* 30 */ {SEL1(0x88888889ul) 0, 4, {2, 6, 0x2b73a840ul SEL2(0x790fc511ul)}},
+  /* 31 */ {SEL1(0x08421085ul) 1, 5, {2, 6, 0x34e63b41ul SEL2(0x35b865a0ul)}},
+  /* 32 */ {SEL1(0ul) 1, 5, {1, 6, 0x40000000ul SEL2(0xfffffffful)}},
+  /* 33 */ {SEL1(0x3e0f83e1ul) 0, 3, {1, 6, 0x4cfa3cc1ul SEL2(0xa9aed1b3ul)}},
+  /* 34 */ {SEL1(0xf0f0f0f1ul) 0, 5, {1, 6, 0x5c13d840ul SEL2(0x63dfc229ul)}},
+  /* 35 */ {SEL1(0xd41d41d5ul) 1, 6, {1, 6, 0x6d91b519ul SEL2(0x2b0fee30ul)}},
+  /* 36 */ {SEL1(0x38e38e39ul) 0, 3, {0, 6, 0x81bf1000ul SEL2(0xf91bd1b6ul)}}
+#endif
+};
+
+/* Lower-case digits.  */
+static const char _itoa_lower_digits[]
+	= "0123456789abcdefghijklmnopqrstuvwxyz";
+/* Upper-case digits.  */
+static const char _itoa_upper_digits[]
+	= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+
+char *
+_itoa (value, buflim, base, upper_case)
+     unsigned long long int value;
+     char *buflim;
+     unsigned int base;
+     int upper_case;
+{
+  const char *digits = upper_case ? _itoa_upper_digits : _itoa_lower_digits;
+  char *bp = buflim;
+  const struct base_table_t *brec = &base_table[base - 2];
+
+  switch (base)
+    {
+#define RUN_2N(BITS)							  \
+      do								  \
+        {								  \
+	  /* `unsigned long long int' always has 64 bits.  */		  \
+	  mp_limb work_hi = value >> (64 - BITS_PER_MP_LIMB);		  \
+									  \
+	  if (BITS_PER_MP_LIMB == 32)					  \
+	    if (work_hi != 0)						  \
+	      {								  \
+		mp_limb work_lo;					  \
+		int cnt;						  \
+									  \
+		work_lo = value & 0xfffffffful;				  \
+		for (cnt = BITS_PER_MP_LIMB / BITS; cnt > 0; --cnt)	  \
+		  {							  \
+		    *--bp = digits[work_lo & ((1ul << BITS) - 1)];	  \
+		    work_lo >>= BITS;					  \
+		  }							  \
+		if (BITS_PER_MP_LIMB % BITS != 0)			  \
+		  {							  \
+		    work_lo |= ((work_hi				  \
+				 & ((1 << BITS - BITS_PER_MP_LIMB % BITS) \
+				    - 1))				  \
+				<< BITS_PER_MP_LIMB % BITS);		  \
+		    *--bp = digits[work_lo];				  \
+		    work_hi >>= BITS - BITS_PER_MP_LIMB % BITS;		  \
+		  }							  \
+	      }								  \
+	    else							  \
+	      work_hi = value & 0xfffffffful;				  \
+	  do								  \
+	    {								  \
+	      *--bp = digits[work_hi & ((1 << BITS) - 1)];		  \
+	      work_hi >>= BITS;						  \
+	    }								  \
+	  while (work_hi != 0);						  \
+	}								  \
+      while (0)
+    case 8:
+      RUN_2N (3);
+      break;
+
+    case 16:
+      RUN_2N (4);
+      break;
+
+    default:
+      {
+#if BITS_PER_MP_LIMB == 64
+	mp_limb base_multiplier = brec->base_multiplier;
+	if (brec->flag)
+	  while (value != 0)
+	    {
+	      mp_limb quo, rem, x, dummy;
+
+	      umul_ppmm (x, dummy, value, base_multiplier);
+	      quo = (x + ((value - x) >> 1)) >> (brec->post_shift - 1);
+	      rem = value - quo * base;
+	      *--bp = digits[rem];
+	      value = quo;
+	    }
+	else
+	  while (value != 0)
+	    {
+	      mp_limb quo, rem, x, dummy;
+
+	      umul_ppmm (x, dummy, value, base_multiplier);
+	      quo = x >> brec->post_shift;
+	      rem = value - quo * base;
+	      *--bp = digits[rem];
+	      value = quo;
+	    }
+#endif
+#if BITS_PER_MP_LIMB == 32
+	mp_limb 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) (value >> 32) >= 1)
+	  {
+	    int big_normalization_steps = brec->big.normalization_steps;
+	    mp_limb big_base_norm = brec->big.base << big_normalization_steps;
+
+	    if ((mp_limb) (value >> 32) >= brec->big.base)
+	      {
+		mp_limb 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 x, xh, xl;
+
+		if (big_normalization_steps == 0)
+		  xh = 0;
+		else
+		  xh = (mp_limb) (value >> 64 - big_normalization_steps);
+		xl = (mp_limb) (value >> 32 - big_normalization_steps);
+		udiv_qrnnd_preinv (x1hi, r, xh, xl, big_base_norm,
+				   brec->big.base_ninv);
+
+		xl = ((mp_limb) value) << big_normalization_steps;
+		udiv_qrnnd_preinv (x1lo, x, r, xl, big_base_norm,
+				   big_normalization_steps);
+		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,
+				   big_normalization_steps);
+		t[1] = x >> big_normalization_steps;
+#elif UDIV_NEEDS_NORMALIZATION
+		mp_limb x, xh, xl;
+
+		if (big_normalization_steps == 0)
+		  xh = 0;
+		else
+		  xh = (mp_limb) (value >> 64 - big_normalization_steps);
+		xl = (mp_limb) (value >> 32 - big_normalization_steps);
+		udiv_qrnnd (x1hi, r, xh, xl, big_base_norm);
+
+		xl = ((mp_limb) 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) (value >> 32),
+			    brec->big.base);
+		udiv_qrnnd (x1lo, t[2], r, (mp_limb) 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 x;
+
+		value <<= brec->big.normalization_steps;
+		udiv_qrnnd_preinv (t[0], x, (mp_limb) (value >> 32),
+				   (mp_limb) value, big_base_norm,
+				   brec->big.base_ninv);
+		t[1] = x >> brec->big.normalization_steps;
+#elif UDIV_NEEDS_NORMALIZATION
+		mp_limb x;
+
+		value <<= big_normalization_steps;
+		udiv_qrnnd (t[0], x, (mp_limb) (value >> 32),
+			    (mp_limb) value, big_base_norm);
+		t[1] = x >> big_normalization_steps;
+#else
+		udiv_qrnnd (t[0], t[1], (mp_limb) (value >> 32),
+			    (mp_limb) 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 ti = t[--n];
+	    int ndig_for_this_limb = 0;
+
+#if UDIV_TIME > 2 * UMUL_TIME
+	    mp_limb base_multiplier = brec->base_multiplier;
+	    if (brec->flag)
+	      while (ti != 0)
+		{
+		  mp_limb quo, rem, x, dummy;
+
+		  umul_ppmm (x, dummy, ti, base_multiplier);
+		  quo = (x + ((ti - x) >> 1)) >> (brec->post_shift - 1);
+		  rem = ti - quo * base;
+		  *--bp = digits[rem];
+		  ti = quo;
+		  ++ndig_for_this_limb;
+		}
+	    else
+	      while (ti != 0)
+		{
+		  mp_limb quo, rem, x, dummy;
+
+		  umul_ppmm (x, dummy, ti, base_multiplier);
+		  quo = x >> brec->post_shift;
+		  rem = ti - quo * base;
+		  *--bp = digits[rem];
+		  ti = quo;
+		  ++ndig_for_this_limb;
+		}
+#else
+	    while (ti != 0)
+	      {
+		mp_limb quo, rem;
+
+		quo = ti / base;
+		rem = ti % base;
+		*--bp = digits[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)
+		{
+		  *--bp = '0';
+		  ++ndig_for_this_limb;
+		}
+	  }
+	while (n != 0);
+#endif
+      }
+      break;
+    }
+
+  return bp;
+}
diff --git a/stdio-common/_itoa.h b/stdio-common/_itoa.h
new file mode 100644
index 0000000000..ab3d1d1d3a
--- /dev/null
+++ b/stdio-common/_itoa.h
@@ -0,0 +1,32 @@
+/* Internal function for converting integers to ASCII.
+Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef _ITOA_H
+#define _ITOA_H
+#include <sys/cdefs.h>
+
+/* Convert VALUE into ASCII in base BASE (2..36).
+   Write backwards starting the character just before BUFLIM.
+   Return the address of the first (left-to-right) character in the number.
+   Use upper case letters iff UPPER_CASE is nonzero.  */
+
+extern char *_itoa __P ((unsigned long long int value, char *buflim,
+			 unsigned int base, int upper_case));
+
+#endif	/* itoa.h */
diff --git a/stdio-common/asprintf.c b/stdio-common/asprintf.c
new file mode 100644
index 0000000000..85ab7b1041
--- /dev/null
+++ b/stdio-common/asprintf.c
@@ -0,0 +1,42 @@
+/* Copyright (C) 1991, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifdef USE_IN_LIBIO
+# define vasprintf _IO_vasprintf
+#endif
+
+/* Write formatted output from FORMAT to a string which is
+   allocated with malloc and stored in *STRING_PTR.  */
+/* VARARGS2 */
+int
+asprintf (string_ptr, format)
+     char **string_ptr;
+     const char *format;
+{
+  va_list arg;
+  int done;
+
+  va_start (arg, format);
+  done = vasprintf (string_ptr, format, arg);
+  va_end (arg);
+
+  return done;
+}
diff --git a/stdio-common/bug1.c b/stdio-common/bug1.c
new file mode 100644
index 0000000000..755bc4231b
--- /dev/null
+++ b/stdio-common/bug1.c
@@ -0,0 +1,28 @@
+#include <ansidecl.h>
+#include <stdio.h>
+#include <string.h>
+
+int
+DEFUN_VOID(main)
+{
+  char *bp;
+  size_t size;
+  FILE *stream;
+  int lose = 0;
+
+  stream = open_memstream (&bp, &size);
+  fprintf (stream, "hello");
+  fflush (stream);
+  printf ("buf = %s, size = %d\n", bp, size);
+  lose |= size != 5;
+  lose |= strncmp (bp, "hello", size);
+  fprintf (stream, ", world");
+  fclose (stream);
+  printf ("buf = %s, size = %d\n", bp, size);
+  lose |= size != 12;
+  lose |= strncmp (bp, "hello, world", 12);
+
+  puts (lose ? "Test FAILED!" : "Test succeeded.");
+
+  return lose;
+}
diff --git a/stdio-common/bug1.input b/stdio-common/bug1.input
new file mode 100644
index 0000000000..5595fa46c0
--- /dev/null
+++ b/stdio-common/bug1.input
@@ -0,0 +1 @@
+95
diff --git a/stdio-common/bug2.c b/stdio-common/bug2.c
new file mode 100644
index 0000000000..2b34c890bf
--- /dev/null
+++ b/stdio-common/bug2.c
@@ -0,0 +1,12 @@
+#include <ansidecl.h>
+#include <stdio.h>
+
+int
+DEFUN_VOID(main)
+{
+  int i;
+  puts ("This should print \"wow = I\" for I from 0 to 39 inclusive.");
+  for (i = 0; i < 40; i++)
+    printf ("%s = %d\n", "wow", i);
+  return 0;
+}
diff --git a/stdio-common/bug3.c b/stdio-common/bug3.c
new file mode 100644
index 0000000000..1684720b9f
--- /dev/null
+++ b/stdio-common/bug3.c
@@ -0,0 +1,52 @@
+#include <ansidecl.h>
+#include <stdio.h>
+#include <string.h>
+
+int
+DEFUN_VOID(main)
+{
+  FILE *f;
+  int i;
+
+  f = fopen("/tmp/bugtest", "w+");
+  for (i=0; i<9000; i++)
+    putc ('x', f);
+  fseek (f, 8180L, 0);
+  fwrite ("Where does this text go?", 1, 24, f);
+  fflush (f);
+
+  rewind (f);
+  for (i=0; i<9000; i++)
+    {
+      int j;
+
+      if ((j = getc(f)) != 'x')
+	{
+	  if (i != 8180)
+	    {
+	      printf ("Test FAILED!");
+	      return 1;
+	    }
+	  else
+	    {
+	      char buf[25];
+
+	      buf[0] = j;
+	      fread (buf + 1, 1, 23, f);
+	      buf[24] = '\0';
+	      if (strcmp (buf, "Where does this text go?") != 0)
+		{
+		  printf ("%s\nTest FAILED!\n", buf);
+		  return 1;
+		}
+	      i += 23;
+	    }
+	}
+    }
+
+  fclose(f);
+
+  puts ("Test succeeded.");
+
+  return 0;
+}
diff --git a/stdio-common/bug4.c b/stdio-common/bug4.c
new file mode 100644
index 0000000000..00abf3c502
--- /dev/null
+++ b/stdio-common/bug4.c
@@ -0,0 +1,50 @@
+#ifdef _LIBC
+#include <ansidecl.h>
+#endif
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+int stdio_block_read = 1, stdio_block_write = 1;
+
+int
+DEFUN(main, (argc, argv),
+      int argc AND char **argv)
+{
+  FILE *f;
+  int i;
+  char buffer[31];
+
+  while ((i = getopt (argc, argv, "rw")) != EOF)
+    switch (i)
+      {
+      case 'r':
+	stdio_block_read = 0;
+	break;
+      case 'w':
+	stdio_block_write = 0;
+	break;
+      }
+
+  f = fopen("/tmp/bugtest", "w+");
+  for (i=0; i<9000; i++) {
+    putc('x', f);
+  }
+  fseek(f, 8180L, 0);
+  fwrite("Where does this text come from?", 1, 31, f);
+  fseek(f, 8180L, 0);
+  fread(buffer, 1, 31, f);
+  fwrite(buffer, 1, 31, stdout);
+  fclose(f);
+
+  if (!memcmp (buffer, "Where does this text come from?", 31))
+    {
+      puts ("\nTest succeeded.");
+      return 0;
+    }
+  else
+    {
+      puts ("\nTest FAILED!");
+      return 1;
+    }
+}
diff --git a/stdio-common/bug5.c b/stdio-common/bug5.c
new file mode 100644
index 0000000000..18f069ae29
--- /dev/null
+++ b/stdio-common/bug5.c
@@ -0,0 +1,60 @@
+/* If stdio is working correctly, after this is run infile and outfile
+   will have the same contents.  If the bug (found in GNU C library 0.3)
+   exhibits itself, outfile will be missing the 2nd through 1023rd
+   characters.  */
+
+#include <ansidecl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static char buf[8192];
+
+int
+DEFUN_VOID(main)
+{
+  FILE *in;
+  FILE *out;
+  static char inname[] = "/tmp/bug5.in";
+  static char outname[] = "/tmp/bug5.out";
+  int i;
+
+  /* Create a test file.  */
+  in = fopen (inname, "w+");
+  if (in == NULL)
+    {
+      perror (inname);
+      return 1;
+    }
+  for (i = 0; i < 1000; ++i)
+    fprintf (in, "%d\n", i);
+
+  out = fopen (outname, "w");
+  if (out == NULL)
+    {
+      perror (outname);
+      return 1;
+    }
+  if (fseek (in, 0L, SEEK_SET) != 0)
+    abort ();
+  putc (getc (in), out);
+  i = fread (buf, 1, sizeof (buf), in);
+  if (i == 0)
+    {
+      perror ("fread");
+      return 1;
+    }
+  if (fwrite (buf, 1, i, out) != i)
+    {
+      perror ("fwrite");
+      return 1;
+    }
+  fclose (in);
+  fclose (out);
+
+  puts ("There should be no further output from this test.");
+  fflush (stdout);
+  execlp ("cmp", "cmp", inname, outname, (char *) NULL);
+  perror ("execlp: cmp");
+  exit (1);
+}
diff --git a/stdio-common/bug6.c b/stdio-common/bug6.c
new file mode 100644
index 0000000000..4a37ab2584
--- /dev/null
+++ b/stdio-common/bug6.c
@@ -0,0 +1,27 @@
+#include <ansidecl.h>
+#include <stdio.h>
+
+int
+DEFUN_VOID(main)
+{
+  char buf[80];
+  int i;
+  int lost = 0;
+
+  scanf ("%2s", buf);
+  lost |= (buf[0] != 'X' || buf[1] != 'Y' || buf[2] != '\0');
+  if (lost)
+    puts ("test of %2s failed.");
+  scanf (" ");
+  scanf ("%d", &i);
+  lost |= (i != 1234);
+  if (lost)
+    puts ("test of %d failed.");
+  scanf ("%c", buf);
+  lost |= (buf[0] != 'L');
+  if (lost)
+    puts ("test of %c failed.\n");
+
+  puts (lost ? "Test FAILED!" : "Test succeeded.");
+  return lost;
+}
diff --git a/stdio-common/bug6.input b/stdio-common/bug6.input
new file mode 100644
index 0000000000..d996e399c3
--- /dev/null
+++ b/stdio-common/bug6.input
@@ -0,0 +1 @@
+XY 1234L
diff --git a/stdio-common/bug7.c b/stdio-common/bug7.c
new file mode 100644
index 0000000000..af06f8d6a5
--- /dev/null
+++ b/stdio-common/bug7.c
@@ -0,0 +1,53 @@
+/* Regression test for fseek and freopen bugs.  */
+
+#include <stdio.h>
+
+int
+main ()
+{
+  int lose = 0;
+  char filename[] = "/tmp/foo";
+  FILE *fp;
+ 
+  fp = fopen (filename, "w+");
+  fprintf (fp, "Hello world!\n");
+  fflush (fp);
+  fseek (fp, 5L, SEEK_SET);
+  if (fseek (fp, -1L, SEEK_CUR) < 0)
+    {
+      printf ("seek failed\n");
+      lose = 1;
+    }
+  fclose (fp);
+  remove (filename);
+
+  {
+    FILE *file1;
+    FILE *file2;
+    char filename1[] = "/tmp/foo";
+    char filename2[] = "/tmp/bar";
+    int ch;
+
+    file1 = fopen (filename1, "w");
+    fclose (file1);
+
+    file2 = fopen (filename2, "w");
+    fputc ('x', file2);
+    fclose (file2);
+
+    file1 = fopen (filename1, "r");
+    file2 = freopen (filename2, "r", file1);
+    if ((ch = fgetc (file2)) != 'x')
+      {
+	printf ("wrong character in reopened file, value = %d\n", ch);
+	lose = 1;
+      }
+    fclose (file1);
+    fclose (file2);
+    remove (filename1);
+    remove (filename2);
+  }
+
+  puts (lose ? "Test FAILED!" : "Test succeeded.");
+  return lose;
+}
diff --git a/stdio-common/dprintf.c b/stdio-common/dprintf.c
new file mode 100644
index 0000000000..5746d49841
--- /dev/null
+++ b/stdio-common/dprintf.c
@@ -0,0 +1,41 @@
+/* Copyright (C) 1991, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifdef USE_IN_LIBIO
+# define vdprintf _IO_vdprintf
+#endif
+
+/* Write formatted output to D, according to the format string FORMAT.  */
+/* VARARGS2 */
+int
+dprintf (d, format)
+     int d;
+     const char *format;
+{
+  va_list arg;
+  int done;
+
+  va_start (arg, format);
+  done = vdprintf (d, format, arg);
+  va_end (arg);
+
+  return done;
+}
diff --git a/stdio-common/errnobug.c b/stdio-common/errnobug.c
new file mode 100644
index 0000000000..cf17be30a2
--- /dev/null
+++ b/stdio-common/errnobug.c
@@ -0,0 +1,60 @@
+/* Regression test for reported old bug that errno is clobbered
+   by the first successful output to a stream on an unseekable object. 
+Copyright (C) 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int
+main (void)
+{
+  int fd[2];
+  FILE *f;
+
+  /* Get a stream that cannot seek.  */
+
+  if (pipe (fd))
+    {
+      perror ("pipe");
+      return 1;
+    }
+  f = fdopen (fd[1], "w");
+  if (f == NULL)
+    {
+      perror ("fdopen");
+      return 1;
+    }
+
+  errno = 0;
+  if (fputs ("fnord", f))
+    {
+      perror ("fputs");
+      return 1;
+    }
+
+  if (errno)
+    {
+      perror ("errno gratuitously set -- TEST FAILED");
+      return 1;
+    }
+
+  puts ("Test succeeded.");
+  return 0;
+}
diff --git a/stdio-common/fprintf.c b/stdio-common/fprintf.c
new file mode 100644
index 0000000000..bc6d1003b7
--- /dev/null
+++ b/stdio-common/fprintf.c
@@ -0,0 +1,38 @@
+/* Copyright (C) 1991 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+
+/* Write formatted output to STREAM from the format string FORMAT.  */
+/* VARARGS2 */
+int
+DEFUN(fprintf, (stream, format),
+      FILE *stream AND CONST char *format DOTS)
+{
+  va_list arg;
+  int done;
+
+  va_start(arg, format);
+  done = vfprintf(stream, format, arg);
+  va_end(arg);
+
+  return done;
+}
diff --git a/stdio-common/fscanf.c b/stdio-common/fscanf.c
new file mode 100644
index 0000000000..cbe0103368
--- /dev/null
+++ b/stdio-common/fscanf.c
@@ -0,0 +1,38 @@
+/* Copyright (C) 1991 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+
+/* Read formatted input from STREAM according to the format string FORMAT.  */
+/* VARARGS2 */
+int
+DEFUN(fscanf, (stream, format),
+      FILE *stream AND CONST char *format DOTS)
+{
+  va_list arg;
+  int done;
+
+  va_start(arg, format);
+  done = __vfscanf(stream, format, arg);
+  va_end(arg);
+
+  return done;
+}
diff --git a/stdio-common/getline.c b/stdio-common/getline.c
new file mode 100644
index 0000000000..1a2f975c75
--- /dev/null
+++ b/stdio-common/getline.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#undef __getline
+
+/* Like getdelim, but always looks for a newline.  */
+ssize_t
+DEFUN(__getline, (lineptr, n, stream),
+      char **lineptr AND size_t *n AND FILE *stream)
+{
+  return __getdelim (lineptr, n, '\n', stream);
+}
+
+weak_alias (__getline, getline)
diff --git a/stdio-common/getw.c b/stdio-common/getw.c
new file mode 100644
index 0000000000..45d4d8875d
--- /dev/null
+++ b/stdio-common/getw.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 1991 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <stdio.h>
+
+
+/* Read a word (int) from STREAM.  */
+int
+DEFUN(getw, (stream), FILE *stream)
+{
+	int w;
+
+	/* Is there a better way?  */
+	if (fread((PTR) &w, sizeof(w), 1, stream) != 1)
+	  return(EOF);
+	return(w);
+}
diff --git a/stdio-common/perror.c b/stdio-common/perror.c
new file mode 100644
index 0000000000..1054acaa7d
--- /dev/null
+++ b/stdio-common/perror.c
@@ -0,0 +1,42 @@
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <stdio.h>
+#include <errno.h>
+
+extern char *_strerror_internal __P ((int, char *buf, size_t));
+
+/* Print a line on stderr consisting of the text in S, a colon, a space,
+   a message describing the meaning of the contents of `errno' and a newline.
+   If S is NULL or "", the colon and space are omitted.  */
+void
+DEFUN(perror, (s), register CONST char *s)
+{
+  char buf[1024];
+  int errnum = errno;
+  CONST char *colon;
+
+  if (s == NULL || *s == '\0')
+    s = colon = "";
+  else
+    colon = ": ";
+
+  (void) fprintf (stderr, "%s%s%s\n",
+		  s, colon, _strerror_internal (errnum, buf, sizeof buf));
+}
diff --git a/stdio-common/printf-parse.h b/stdio-common/printf-parse.h
new file mode 100644
index 0000000000..0f6e9e287b
--- /dev/null
+++ b/stdio-common/printf-parse.h
@@ -0,0 +1,388 @@
+/* Internal header for parsing printf format strings.
+Copyright (C) 1995 Free Software Foundation, Inc.
+This file is part of th GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ctype.h>
+#include <printf.h>
+#include <string.h>
+#include <stddef.h>
+
+#define NDEBUG 1
+#include <assert.h>
+
+#define MAX(a,b)	({typeof(a) _a = (a); typeof(b) _b = (b);	      \
+			  _a > _b ? _a : _b; })
+#define MIN(a,b)	({typeof(a) _a = (a); typeof(b) _b = (b);	      \
+			  _a < _b ? _a : _b; })
+
+struct printf_spec
+  {
+    /* Information parsed from the format spec.  */ 
+    struct printf_info info;
+
+    /* Pointers into the format string for the end of this format
+       spec and the next (or to the end of the string if no more).  */
+    const char *end_of_fmt, *next_fmt;
+
+    /* Position of arguments for precision and width, or -1 if `info' has
+       the constant value.  */
+    int prec_arg, width_arg;
+
+    int data_arg;		/* Position of data argument.  */
+    int data_arg_type;		/* Type of first argument.  */
+    /* Number of arguments consumed by this format specifier.  */
+    size_t ndata_args;
+  };
+
+
+/* The various kinds off arguments that can be passed to printf.  */
+union printf_arg
+  {
+    unsigned char pa_char;
+    short int pa_short_int;
+    int pa_int;
+    long int pa_long_int;
+    long long int pa_long_long_int;
+    unsigned short int pa_u_short_int;
+    unsigned int pa_u_int;
+    unsigned long int pa_u_long_int;
+    unsigned long long int pa_u_long_long_int;
+    float pa_float;
+    double pa_double;
+    long double pa_long_double;
+    const char *pa_string;
+    void *pa_pointer;
+  };
+
+
+/* Read a simple integer from a string and update the string pointer.
+   It is assumed that the first character is a digit.  */
+static inline unsigned int
+read_int (const char * *pstr)
+{
+  unsigned int retval = **pstr - '0';
+
+  while (isdigit (*++(*pstr)))
+    {
+      retval *= 10;
+      retval += **pstr - '0';
+    }
+
+  return retval;
+}
+
+
+
+/* Find the next spec in FORMAT, or the end of the string.  Returns
+   a pointer into FORMAT, to a '%' or a '\0'.  */
+static inline const char *
+find_spec (const char *format)
+{
+  while (*format != '\0' && *format != '%')
+    {
+      int len;
+
+      if (isascii (*format) || (len = mblen (format, MB_CUR_MAX)) <= 0)
+	++format;
+      else
+	format += len;
+    }
+  return format;
+}
+
+
+/* This is defined in reg-printf.c.  */
+extern printf_arginfo_function **__printf_arginfo_table;
+
+
+/* FORMAT must point to a '%' at the beginning of a spec.  Fills in *SPEC
+   with the parsed details.  POSN is the number of arguments already
+   consumed.  At most MAXTYPES - POSN types are filled in TYPES.  Return
+   the number of args consumed by this spec; *MAX_REF_ARG is updated so it
+   remains the highest argument index used.  */
+static inline size_t
+parse_one_spec (const char *format, size_t posn, struct printf_spec *spec,
+		size_t *max_ref_arg)
+{
+  unsigned int n;
+  size_t nargs = 0;
+
+  /* Skip the '%'.  */
+  ++format;
+
+  /* Clear information structure.  */
+  spec->data_arg = -1;
+  spec->info.alt = 0;
+  spec->info.space = 0;
+  spec->info.left = 0;
+  spec->info.showsign = 0;
+  spec->info.group = 0;
+  spec->info.pad = ' ';
+
+  /* Test for positional argument.  */
+  if (isdigit (*format))
+    {
+      const char *begin = format;
+
+      n = read_int (&format);
+
+      if (n > 0 && *format == '$')
+	/* Is positional parameter.  */
+	{
+	  ++format;		/* Skip the '$'.  */
+	  spec->data_arg = n - 1;
+	  *max_ref_arg = MAX (*max_ref_arg, n);
+	}
+      else
+	/* Oops; that was actually the width and/or 0 padding flag.
+	   Step back and read it again.  */
+	format = begin;
+    }
+
+  /* Check for spec modifiers.  */
+  while (*format == ' ' || *format == '+' || *format == '-' ||
+	 *format == '#' || *format == '0' || *format == '\'')
+    switch (*format++)
+      {
+      case ' ':
+	/* Output a space in place of a sign, when there is no sign.  */
+	spec->info.space = 1;
+	break;
+      case '+':
+	/* Always output + or - for numbers.  */
+	spec->info.showsign = 1;
+	break;
+      case '-':
+	/* Left-justify things.  */
+	spec->info.left = 1;
+	break;
+      case '#':
+	/* Use the "alternate form":
+	   Hex has 0x or 0X, FP always has a decimal point.  */
+	spec->info.alt = 1;
+	break;
+      case '0':
+	/* Pad with 0s.  */
+	spec->info.pad = '0';
+	break;
+      case '\'':
+	/* Show grouping in numbers if the locale information
+	   indicates any.  */
+	spec->info.group = 1;
+	break;
+      }
+  if (spec->info.left)
+    spec->info.pad = ' ';
+
+  /* Get the field width.  */
+  spec->width_arg = -1;
+  spec->info.width = 0;
+  if (*format == '*')
+    {
+      /* The field width is given in an argument.
+	 A negative field width indicates left justification.  */
+      const char *begin = ++format;
+
+      if (isdigit (*format))
+	{
+	  /* The width argument might be found in a positional parameter.  */
+	  n = read_int (&format);
+
+	  if (n > 0 && *format == '$')
+	    {
+	      spec->width_arg = n - 1;
+	      *max_ref_arg = MAX (*max_ref_arg, n);
+	      ++format;		/* Skip '$'.  */
+	    }
+	}
+
+      if (spec->width_arg < 0)
+	{
+	  /* Not in a positional parameter.  Consume one argument.  */
+	  spec->width_arg = posn++;
+	  ++nargs;
+	  format = begin;	/* Step back and reread.  */
+	}
+    }
+  else if (isdigit (*format))
+    /* Constant width specification.  */
+    spec->info.width = read_int (&format);
+
+  /* Get the precision.  */
+  spec->prec_arg = -1;
+  /* -1 means none given; 0 means explicit 0.  */
+  spec->info.prec = -1;
+  if (*format == '.')
+    {
+      ++format;
+      if (*format == '*')
+	{
+	  /* The precision is given in an argument.  */
+	  const char *begin = ++format;
+
+	  if (isdigit (*format))
+	    {
+	      n = read_int (&format);
+
+	      if (n > 0 && *format == '$')
+		{
+		  spec->prec_arg = n - 1;
+		  *max_ref_arg = MAX (*max_ref_arg, n);
+		  ++format;
+		}
+	    }
+
+	  if (spec->prec_arg < 0)
+	    {
+	      /* Not in a positional parameter.  */
+	      spec->prec_arg = posn++;
+	      ++nargs;
+	      format = begin;
+	    }
+	}
+      else if (isdigit (*format))
+	spec->info.prec = read_int (&format);
+      else
+	/* "%.?" is treated like "%.0?".  */
+	spec->info.prec = 0;
+
+      /* If there was a precision specified, ignore the 0 flag and always
+	 pad with spaces.  */
+      spec->info.pad = ' ';
+    }
+
+  /* Check for type modifiers.  */
+#define is_longlong is_long_double
+  spec->info.is_long_double = 0;
+  spec->info.is_short = 0;
+  spec->info.is_long = 0;
+
+  while (*format == 'h' || *format == 'l' || *format == 'L' ||
+	 *format == 'Z' || *format == 'q')
+    switch (*format++)
+      {
+      case 'h':
+	/* int's are short int's.  */
+	spec->info.is_short = 1;
+	break;
+      case 'l':
+	if (spec->info.is_long)
+	  /* A double `l' is equivalent to an `L'.  */
+	  spec->info.is_longlong = 1;
+	else
+	  /* int's are long int's.  */
+	  spec->info.is_long = 1;
+	break;
+      case 'L':
+	/* double's are long double's, and int's are long long int's.  */
+	spec->info.is_long_double = 1;
+	break;
+      case 'Z':
+	/* int's are size_t's.  */
+	assert (sizeof(size_t) <= sizeof(unsigned long long int));
+	spec->info.is_longlong = sizeof(size_t) > sizeof(unsigned long int);
+	spec->info.is_long = sizeof(size_t) > sizeof(unsigned int);
+	break;
+      case 'q':
+	/* 4.4 uses this for long long.  */
+	spec->info.is_longlong = 1;
+	break;
+      }
+
+  /* Get the format specification.  */
+  spec->info.spec = *format++;
+  if (__printf_arginfo_table != NULL &&
+      __printf_arginfo_table[spec->info.spec] != NULL)
+    /* We don't try to get the types for all arguments if the format
+       uses more than one.  The normal case is covered though.  */
+    spec->ndata_args = (*__printf_arginfo_table[spec->info.spec])
+      (&spec->info, 1, &spec->data_arg_type);
+  else
+    {
+      /* Find the data argument types of a built-in spec.  */
+      spec->ndata_args = 1;
+
+      switch (spec->info.spec)
+	{
+	case 'i':
+	case 'd':
+	case 'u':
+	case 'o':
+	case 'X':
+	case 'x':
+	  if (spec->info.is_longlong)
+	    spec->data_arg_type = PA_INT|PA_FLAG_LONG_LONG;
+	  else if (spec->info.is_long)
+	    spec->data_arg_type = PA_INT|PA_FLAG_LONG;
+	  else if (spec->info.is_short)
+	    spec->data_arg_type = PA_INT|PA_FLAG_SHORT;
+	  else
+	    spec->data_arg_type = PA_INT;
+	  break;
+	case 'e':
+	case 'E':
+	case 'f':
+	case 'g':
+	case 'G':
+	  if (spec->info.is_long_double)
+	    spec->data_arg_type = PA_DOUBLE|PA_FLAG_LONG_DOUBLE;
+	  else
+	    spec->data_arg_type = PA_DOUBLE;
+	  break;
+	case 'c':
+	  spec->data_arg_type = PA_CHAR;
+	  break;
+	case 's':
+	  spec->data_arg_type = PA_STRING;
+	  break;
+	case 'p':
+	  spec->data_arg_type = PA_POINTER;
+	  break;
+	case 'n':
+	  spec->data_arg_type = PA_INT|PA_FLAG_PTR;
+	  break;
+
+	case 'm':
+	default:
+	  /* An unknown spec will consume no args.  */
+	  spec->ndata_args = 0;
+	  break;
+	}
+
+      if (spec->data_arg == -1 && spec->ndata_args > 0) 
+	{
+	  /* There are args consumed, but no positional spec.
+	     Use the next sequential arg position.  */
+	  spec->data_arg = posn;
+	  posn += spec->ndata_args;
+	  nargs += spec->ndata_args;
+	}
+    }
+
+  if (spec->info.spec == '\0')
+    /* Format ended before this spec was complete.  */
+    spec->end_of_fmt = spec->next_fmt = format - 1;
+  else
+    {
+      /* Find the next format spec.  */
+      spec->end_of_fmt = format;
+      spec->next_fmt = find_spec (format);
+    }
+
+  return nargs;
+}
diff --git a/stdio-common/printf-prs.c b/stdio-common/printf-prs.c
new file mode 100644
index 0000000000..811a9cb7eb
--- /dev/null
+++ b/stdio-common/printf-prs.c
@@ -0,0 +1,72 @@
+/* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <stdio.h>
+#include <printf.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "printf-parse.h"
+
+
+size_t
+parse_printf_format (fmt, n, argtypes)
+      const char *fmt;
+      size_t n;
+      int *argtypes;
+{
+  size_t nargs;			/* Number of arguments.  */
+  size_t max_ref_arg;		/* Highest index used in a positional arg.  */
+  struct printf_spec spec;
+
+  nargs = 0;
+  max_ref_arg = 0;
+
+  /* Search for format specifications.  */
+  for (fmt = find_spec (fmt); *fmt != '\0'; fmt = spec.next_fmt)
+    {
+      /* Parse this spec.  */
+      nargs += parse_one_spec (fmt, nargs, &spec, &max_ref_arg);
+
+      /* If the width is determined by an argument this is an int.  */
+      if (spec.width_arg != -1 && spec.width_arg < n)
+	argtypes[spec.width_arg] = PA_INT;
+
+      /* If the precision is determined by an argument this is an int.  */
+      if (spec.prec_arg != -1 && spec.prec_arg < n)
+	argtypes[spec.prec_arg] = PA_INT;
+
+      if (spec.data_arg < n)
+	switch (spec.ndata_args)
+	  {
+	  case 0:		/* No arguments.  */
+	    break;
+	  case 1:		/* One argument; we already have the type.  */
+	    argtypes[spec.data_arg] = spec.data_arg_type;
+	    break;
+	  default:
+	    /* We have more than one argument for this format spec.  We must
+               call the arginfo function again to determine all the types.  */
+	    (void) (*__printf_arginfo_table[spec.info.spec])
+	      (&spec.info, n - spec.data_arg, &argtypes[spec.data_arg]);
+	    break;
+	  }
+    }
+
+  return MAX (nargs, max_ref_arg);
+}
diff --git a/stdio-common/printf.c b/stdio-common/printf.c
new file mode 100644
index 0000000000..d8aa895a77
--- /dev/null
+++ b/stdio-common/printf.c
@@ -0,0 +1,40 @@
+/* Copyright (C) 1991, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifdef USE_IN_LIBIO
+# define vprintf _IO_vprintf
+#endif
+
+/* Write formatted output to stdout from the format string FORMAT.  */
+/* VARARGS1 */
+int
+printf (format)
+     const char *format;
+{
+  va_list arg;
+  int done;
+
+  va_start (arg, format);
+  done = vprintf (format, arg);
+  va_end (arg);
+
+  return done;
+}
diff --git a/stdio-common/printf.h b/stdio-common/printf.h
new file mode 100644
index 0000000000..0f381c77f4
--- /dev/null
+++ b/stdio-common/printf.h
@@ -0,0 +1,124 @@
+/* Copyright (C) 1991, 1992, 1993, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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, 1992 Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef	_PRINTF_H
+
+#define	_PRINTF_H	1
+#include <features.h>
+
+__BEGIN_DECLS
+
+#define	__need_FILE
+#include <stdio.h>
+#define	__need_size_t
+#include <stddef.h>
+
+
+struct printf_info
+{
+  int prec;			/* Precision.  */
+  int width;			/* Width.  */
+  unsigned char spec;		/* Format letter.  */
+  unsigned int is_long_double:1;/* L flag.  */
+  unsigned int is_short:1;	/* h flag.  */
+  unsigned int is_long:1;	/* l flag.  */
+  unsigned int alt:1;		/* # flag.  */
+  unsigned int space:1;		/* Space flag.  */
+  unsigned int left:1;		/* - flag.  */
+  unsigned int showsign:1;	/* + flag.  */
+  unsigned int group:1;		/* ' flag.  */
+  char pad;			/* Padding character.  */
+};
+
+
+/* Type of a printf specifier-handler function.
+   STREAM is the FILE on which to write output.
+   INFO gives information about the format specification.
+   ARGS is a vector of pointers to the argument data;
+   the number of pointers will be the number returned
+   by the associated arginfo function for the same INFO.
+
+   The function should return the number of characters written,
+   or -1 for errors.  */
+
+typedef int printf_function __P ((FILE *__stream,
+				  __const struct printf_info *__info,
+				  __const void **__const __args));
+
+/* Type of a printf specifier-arginfo function.
+   INFO gives information about the format specification.
+   N, ARGTYPES, and return value are as for printf_parse_format.  */
+
+typedef int printf_arginfo_function __P ((__const struct printf_info * __info,
+					  size_t __n,
+					  int *__argtypes));
+
+
+/* Register FUNC to be called to format SPEC specifiers; ARGINFO must be
+   specified to determine how many arguments a SPEC conversion requires and
+   what their types are, even if your program never calls
+   `parse_printf_format'.  */
+
+extern int register_printf_function __P ((int __spec, printf_function __func,
+					  printf_arginfo_function __arginfo));
+
+
+/* Parse FMT, and fill in N elements of ARGTYPES with the
+   types needed for the conversions FMT specifies.  Returns
+   the number of arguments required by FMT.
+
+   The ARGINFO function registered with a user-defined format is passed a
+   `struct printf_info' describing the format spec being parsed.  A width
+   or precision of INT_MIN means a `*' was used to indicate that the
+   width/precision will come from an arg.  The function should fill in the
+   array it is passed with the types of the arguments it wants, and return
+   the number of arguments it wants.  */
+
+extern size_t parse_printf_format __P ((__const char *__fmt,
+					size_t __n,
+					int *__argtypes));
+
+
+/* Codes returned by `parse_printf_format' for basic types.
+
+   These values cover all the standard format specifications.
+   Users can add new values after PA_LAST for their own types.  */
+
+enum
+{				/* C type: */
+  PA_INT,			/* int */
+  PA_CHAR,			/* int, cast to char */
+  PA_STRING,			/* const char *, a '\0'-terminated string */
+  PA_POINTER,			/* void * */
+  PA_FLOAT,			/* float */
+  PA_DOUBLE,			/* double */
+  PA_LAST
+};
+
+/* Flag bits that can be set in a type returned by `parse_printf_format'.  */
+#define	PA_FLAG_MASK		0xff00
+#define	PA_FLAG_LONG_LONG	(1 << 8)
+#define	PA_FLAG_LONG_DOUBLE	PA_FLAG_LONG_LONG
+#define	PA_FLAG_LONG		(1 << 9)
+#define	PA_FLAG_SHORT		(1 << 10)
+#define	PA_FLAG_PTR		(1 << 11)
+
+
+__END_DECLS
+
+#endif /* printf.h  */
diff --git a/stdio-common/printf_fp.c b/stdio-common/printf_fp.c
new file mode 100644
index 0000000000..28d13d61b8
--- /dev/null
+++ b/stdio-common/printf_fp.c
@@ -0,0 +1,990 @@
+/* Floating point output for `printf'.
+Copyright (C) 1995 Free Software Foundation, Inc.
+Written by Ulrich Drepper.
+
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifdef USE_IN_LIBIO
+#  include <libioP.h>
+#else
+#  include <stdio.h>
+#endif
+#include <alloca.h>
+#include <ansidecl.h>
+#include <ctype.h>
+#include <float.h>
+#include <gmp-mparam.h>
+#include "../stdlib/gmp.h"
+#include "../stdlib/gmp-impl.h"
+#include "../stdlib/longlong.h"
+#include "../stdlib/fpioconst.h"
+#include "../locale/localeinfo.h"
+#include <limits.h>
+#include <math.h>
+#include <printf.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define NDEBUG			/* Undefine this for debugging assertions.  */
+#include <assert.h>
+
+/* This defines make it possible to use the same code for GNU C library and
+   the GNU I/O library.	 */
+#ifdef USE_IN_LIBIO
+#  define PUT(f, s, n) _IO_sputn (f, s, n)
+#  define PAD(f, c, n) _IO_padn (f, c, n)
+/* We use this file GNU C library and GNU I/O library.	So make
+   names equal.	 */
+#  undef putc
+#  define putc(c, f) _IO_putc (c, f)
+#  define size_t     _IO_size_t
+#  define FILE	     _IO_FILE
+#else	/* ! USE_IN_LIBIO */
+#  define PUT(f, s, n) fwrite (s, 1, n, f)
+#  define PAD(f, c, n) __printf_pad (f, c, n)
+ssize_t __printf_pad __P ((FILE *, char pad, int n)); /* In vfprintf.c.  */
+#endif	/* USE_IN_LIBIO */
+
+/* Macros for doing the actual output.  */
+
+#define outchar(ch)							      \
+  do									      \
+    {									      \
+      register CONST int outc = (ch);					      \
+      if (putc (outc, fp) == EOF)					      \
+	return -1;							      \
+      ++done;								      \
+    } while (0)
+
+#define PRINT(ptr, len)							      \
+  do									      \
+    {									      \
+      register size_t outlen = (len);					      \
+      if (len > 20)							      \
+	{								      \
+	  if (PUT (fp, ptr, outlen) != outlen)				      \
+	    return -1;							      \
+	  ptr += outlen;						      \
+	  done += outlen;						      \
+	}								      \
+      else								      \
+	{								      \
+	  while (outlen-- > 0)						      \
+	    outchar (*ptr++);						      \
+	}								      \
+    } while (0)
+
+#define PADN(ch, len)							      \
+  do									      \
+    {									      \
+      if (PAD (fp, ch, len) != len)					      \
+	return -1;							      \
+      done += len;							      \
+    }									      \
+  while (0)
+
+/* We use the GNU MP library to handle large numbers.
+
+   An MP variable occupies a varying number of entries in its array.  We keep
+   track of this number for efficiency reasons.  Otherwise we would always
+   have to process the whole array.  */
+#define MPN_VAR(name) mp_limb *name; mp_size_t name##size
+
+#define MPN_ASSIGN(dst,src)						      \
+  memcpy (dst, src, (dst##size = src##size) * sizeof (mp_limb))
+#define MPN_GE(u,v) \
+  (u##size > v##size || (u##size == v##size && __mpn_cmp (u, v, u##size) >= 0))
+
+extern int __isinfl (long double), __isnanl (long double);
+
+extern mp_size_t __mpn_extract_double (mp_ptr res_ptr, mp_size_t size,
+				       int *expt, int *is_neg,
+				       double value);
+extern mp_size_t __mpn_extract_long_double (mp_ptr res_ptr, mp_size_t size,
+					    int *expt, int *is_neg,
+					    long double value);
+
+
+static unsigned int guess_grouping (unsigned int intdig_max,
+				    const char *grouping, wchar_t sepchar);
+static char *group_number (char *buf, char *bufend, unsigned int intdig_no,
+			   const char *grouping, wchar_t thousands_sep);
+
+
+int
+__printf_fp (fp, info, args)
+     FILE *fp;
+     const struct printf_info *info;
+     const **const args;
+{
+  /* The floating-point value to output.  */
+  union
+    {
+      double dbl;
+      LONG_DOUBLE ldbl;
+    }
+  fpnum;
+
+  /* Locale-dependent representation of decimal point.	*/
+  wchar_t decimal;
+
+  /* Locale-dependent thousands separator and grouping specification.  */
+  wchar_t thousands_sep;
+  const char *grouping;
+
+  /* "NaN" or "Inf" for the special cases.  */
+  CONST char *special = NULL;
+
+  /* We need just a few limbs for the input before shifting to the right
+     position.	*/
+  mp_limb fp_input[(LDBL_MANT_DIG + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB];
+  /* We need to shift the contents of fp_input by this amount of bits.	*/
+  int to_shift;
+
+  /* The significant of the floting-point value in question  */
+  MPN_VAR(frac);
+  /* and the exponent.	*/
+  int exponent;
+  /* Sign of the exponent.  */
+  int expsign = 0;
+  /* Sign of float number.  */
+  int is_neg = 0;
+
+  /* Scaling factor.  */
+  MPN_VAR(scale);
+
+  /* Temporary bignum value.  */
+  MPN_VAR(tmp);
+
+  /* Digit which is result of last hack_digit() call.  */
+  int digit;
+
+  /* The type of output format that will be used: 'e'/'E' or 'f'.  */
+  int type;
+
+  /* Counter for number of written characters.	*/
+  int done = 0;
+
+  /* General helper (carry limb).  */
+  mp_limb cy;
+
+  char hack_digit (void)
+    {
+      mp_limb hi;
+
+      if (expsign != 0 && type == 'f' && exponent-- > 0)
+	hi = 0;
+      else if (scalesize == 0)
+	{
+	  hi = frac[fracsize - 1];
+	  cy = __mpn_mul_1 (frac, frac, fracsize - 1, 10);
+	  frac[fracsize - 1] = cy;
+	}
+      else
+	{
+	  if (fracsize < scalesize)
+	    hi = 0;
+	  else
+	    {
+	      hi = __mpn_divmod (tmp, frac, fracsize, scale, scalesize);
+	      tmp[fracsize - scalesize] = hi;
+	      hi = tmp[0];
+
+	      fracsize = __mpn_normal_size (frac, scalesize);
+	      if (fracsize == 0)
+		{
+		  /* We're not prepared for an mpn variable with zero
+		     limbs.  */
+		  fracsize = 1;
+		  return '0' + hi;
+		}
+	    }
+
+	  cy = __mpn_mul_1 (frac, frac, fracsize, 10);
+	  if (cy != 0)
+	    frac[fracsize++] = cy;
+	}
+
+      return '0' + hi;
+    }
+
+
+  /* Figure out the decimal point character.  */
+  if (mbtowc (&decimal, _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT),
+	      strlen (_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT))) <= 0)
+    decimal = (wchar_t) *_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
+
+
+  if (info->group)
+    {
+      grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
+      if (*grouping <= 0 || *grouping == CHAR_MAX)
+	grouping = NULL;
+      else
+	{
+	  /* Figure out the thousands seperator character.  */
+	  if (mbtowc (&thousands_sep, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP),
+		      strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0)
+	    thousands_sep = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
+	  if (thousands_sep == L'\0')
+	    grouping = NULL;
+	}
+    }
+  else
+    grouping = NULL;
+
+  /* Fetch the argument value.	*/
+  if (info->is_long_double && sizeof (long double) > sizeof (double))
+    {
+      fpnum.ldbl = *(const long double *) args[0];
+
+      /* Check for special values: not a number or infinity.  */
+      if (__isnanl (fpnum.ldbl))
+	{
+	  special = "NaN";
+	  is_neg = 0;
+	}
+      else if (__isinfl (fpnum.ldbl))
+	{
+	  special = "Inf";
+	  is_neg = fpnum.ldbl < 0;
+	}
+      else
+	{
+	  fracsize = __mpn_extract_long_double (fp_input,
+						(sizeof (fp_input) /
+						 sizeof (fp_input[0])), 
+						&exponent, &is_neg,
+						fpnum.ldbl);
+	  to_shift = 1 + fracsize * BITS_PER_MP_LIMB - LDBL_MANT_DIG;
+	}
+    }
+  else
+    {
+      fpnum.dbl = *(const double *) args[0];
+
+      /* Check for special values: not a number or infinity.  */
+      if (__isnan (fpnum.dbl))
+	{
+	  special = "NaN";
+	  is_neg = 0;
+	}
+      else if (__isinf (fpnum.dbl))
+	{
+	  special = "Inf";
+	  is_neg = fpnum.dbl < 0;
+	}
+      else
+	{
+	  fracsize = __mpn_extract_double (fp_input,
+					   (sizeof (fp_input)
+					    / sizeof (fp_input[0])),
+					   &exponent, &is_neg, fpnum.dbl);
+	  to_shift = 1 + fracsize * BITS_PER_MP_LIMB - DBL_MANT_DIG;
+	}
+    }
+
+  if (special)
+    {
+      int width = info->prec > info->width ? info->prec : info->width;
+
+      if (is_neg || info->showsign || info->space)
+	--width;
+      width -= 3;
+
+      if (!info->left && width > 0)
+	PADN (' ', width);
+
+      if (is_neg)
+	outchar ('-');
+      else if (info->showsign)
+	outchar ('+');
+      else if (info->space)
+	outchar (' ');
+
+      PRINT (special, 3);
+
+      if (info->left && width > 0)
+	PADN (' ', width);
+
+      return done;
+    }
+
+
+  /* We need three multiprecision variables.  Now that we have the exponent
+     of the number we can allocate the needed memory.  It would be more
+     efficient to use variables of the fixed maximum size but because this
+     would be really big it could lead to memory problems.  */
+  {
+    mp_size_t bignum_size = ((ABS (exponent) + BITS_PER_MP_LIMB - 1)
+			     / BITS_PER_MP_LIMB + 3) * sizeof (mp_limb);
+    frac = (mp_limb *) alloca (bignum_size);
+    tmp = (mp_limb *) alloca (bignum_size);
+    scale = (mp_limb *) alloca (bignum_size);
+  }
+
+  /* We now have to distinguish between numbers with positive and negative
+     exponents because the method used for the one is not applicable/efficient
+     for the other.  */
+  scalesize = 0;
+  if (exponent > 2)
+    {
+      /* |FP| >= 1.0.  */
+      int scaleexpo = 0;
+      int explog = LDBL_MAX_10_EXP_LOG;
+      int exp10 = 0;
+      const struct mp_power *tens = &_fpioconst_pow10[explog + 1];
+      int cnt_h, cnt_l, i;
+
+      if ((exponent + to_shift) % BITS_PER_MP_LIMB == 0)
+	{
+	  MPN_COPY_DECR (frac + (exponent + to_shift) / BITS_PER_MP_LIMB,
+			 fp_input, fracsize);
+	  fracsize += (exponent + to_shift) / BITS_PER_MP_LIMB;
+	}
+      else
+	{
+	  cy = __mpn_lshift (frac + (exponent + to_shift) / BITS_PER_MP_LIMB,
+			     fp_input, fracsize,
+			     (exponent + to_shift) % BITS_PER_MP_LIMB);
+	  fracsize += (exponent + to_shift) / BITS_PER_MP_LIMB;
+	  if (cy)
+	    frac[fracsize++] = cy;
+	}
+      MPN_ZERO (frac, (exponent + to_shift) / BITS_PER_MP_LIMB);
+
+      assert (tens > &_fpioconst_pow10[0]);
+      do
+	{
+	  --tens;
+
+	  /* The number of the product of two binary numbers with n and m
+	     bits respectively has m+n or m+n-1 bits.	*/
+	  if (exponent >= scaleexpo + tens->p_expo - 1)
+	    {
+	      if (scalesize == 0)
+		MPN_ASSIGN (tmp, tens->array);
+	      else
+		{
+		  cy = __mpn_mul (tmp, scale, scalesize,
+				  tens->array + 2, tens->arraysize - 2);
+		  tmpsize = scalesize + tens->arraysize - 2;
+		  if (cy == 0)
+		    --tmpsize;
+		}
+
+	      if (MPN_GE (frac, tmp))
+		{
+		  int cnt;
+		  MPN_ASSIGN (scale, tmp);
+		  count_leading_zeros (cnt, scale[scalesize - 1]);
+		  scaleexpo = (scalesize - 2) * BITS_PER_MP_LIMB - cnt - 1;
+		  exp10 |= 1 << explog;
+		}
+	    }
+	  --explog;
+	}
+      while (tens > &_fpioconst_pow10[0]);
+      exponent = exp10;
+
+      /* Optimize number representations.  We want to represent the numbers
+	 with the lowest number of bytes possible without losing any
+	 bytes. Also the highest bit in the scaling factor has to be set
+	 (this is a requirement of the MPN division routines).  */
+      if (scalesize > 0)
+	{
+	  /* Determine minimum number of zero bits at the end of
+	     both numbers.  */
+	  for (i = 0; scale[i] == 0 && frac[i] == 0; i++)
+	    ;
+
+	  /* Determine number of bits the scaling factor is misplaced.	*/
+	  count_leading_zeros (cnt_h, scale[scalesize - 1]);
+
+	  if (cnt_h == 0)
+	    {
+	      /* The highest bit of the scaling factor is already set.	So
+		 we only have to remove the trailing empty limbs.  */
+	      if (i > 0)
+		{
+		  MPN_COPY_INCR (scale, scale + i, scalesize - i);
+		  scalesize -= i;
+		  MPN_COPY_INCR (frac, frac + i, fracsize - i);
+		  fracsize -= i;
+		}
+	    }
+	  else
+	    {
+	      if (scale[i] != 0)
+		{
+		  count_trailing_zeros (cnt_l, scale[i]);
+		  if (frac[i] != 0)
+		    {
+		      int cnt_l2;
+		      count_trailing_zeros (cnt_l2, frac[i]);
+		      if (cnt_l2 < cnt_l)
+			cnt_l = cnt_l2;
+		    }
+		}
+	      else
+		count_trailing_zeros (cnt_l, frac[i]);
+
+	      /* Now shift the numbers to their optimal position.  */
+	      if (i == 0 && BITS_PER_MP_LIMB - cnt_h > cnt_l)
+		{
+		  /* We cannot save any memory.	 So just roll both numbers
+		     so that the scaling factor has its highest bit set.  */
+
+		  (void) __mpn_lshift (scale, scale, scalesize, cnt_h);
+		  cy = __mpn_lshift (frac, frac, fracsize, cnt_h);
+		  if (cy != 0)
+		    frac[fracsize++] = cy;
+		}
+	      else if (BITS_PER_MP_LIMB - cnt_h <= cnt_l)
+		{
+		  /* We can save memory by removing the trailing zero limbs
+		     and by packing the non-zero limbs which gain another
+		     free one. */
+
+		  (void) __mpn_rshift (scale, scale + i, scalesize - i,
+				       BITS_PER_MP_LIMB - cnt_h);
+		  scalesize -= i + 1;
+		  (void) __mpn_rshift (frac, frac + i, fracsize - i,
+				       BITS_PER_MP_LIMB - cnt_h);
+		  fracsize -= frac[fracsize - i - 1] == 0 ? i + 1 : i;
+		}
+	      else
+		{
+		  /* We can only save the memory of the limbs which are zero.
+		     The non-zero parts occupy the same number of limbs.  */
+
+		  (void) __mpn_rshift (scale, scale + (i - 1),
+				       scalesize - (i - 1),
+				       BITS_PER_MP_LIMB - cnt_h);
+		  scalesize -= i;
+		  (void) __mpn_rshift (frac, frac + (i - 1),
+				       fracsize - (i - 1),
+				       BITS_PER_MP_LIMB - cnt_h);
+		  fracsize -= frac[fracsize - (i - 1) - 1] == 0 ? i : i - 1;
+		}
+	    }
+	}
+    }
+  else if (exponent < 0)
+    {
+      /* |FP| < 1.0.  */
+      int exp10 = 0;
+      int explog = LDBL_MAX_10_EXP_LOG;
+      const struct mp_power *tens = &_fpioconst_pow10[explog + 1];
+      mp_size_t used_limbs = fracsize - 1;
+
+      /* Now shift the input value to its right place.	*/
+      cy = __mpn_lshift (frac, fp_input, fracsize, to_shift);
+      frac[fracsize++] = cy; 
+      assert (cy == 1 || (frac[fracsize - 2] == 0 && frac[0] == 0));
+
+      expsign = 1;
+      exponent = -exponent;
+
+      assert (tens != &_fpioconst_pow10[0]);
+      do
+	{
+	  --tens;
+
+	  if (exponent >= tens->m_expo)
+	    {
+	      int i, incr, cnt_h, cnt_l;
+	      mp_limb topval[2];
+
+	      /* The __mpn_mul function expects the first argument to be
+		 bigger than the second.  */
+	      if (fracsize < tens->arraysize - 2)
+		cy = __mpn_mul (tmp, &tens->array[2], tens->arraysize - 2,
+				frac, fracsize);
+	      else
+		cy = __mpn_mul (tmp, frac, fracsize,
+				&tens->array[2], tens->arraysize - 2);
+	      tmpsize = fracsize + tens->arraysize - 2;
+	      if (cy == 0)
+		--tmpsize;
+
+	      count_leading_zeros (cnt_h, tmp[tmpsize - 1]); 
+	      incr = (tmpsize - fracsize) * BITS_PER_MP_LIMB
+		     + BITS_PER_MP_LIMB - 1 - cnt_h;
+
+	      assert (incr <= tens->p_expo);
+
+	      /* If we increased the exponent by exactly 3 we have to test
+		 for overflow.	This is done by comparing with 10 shifted
+		 to the right position.	 */
+	      if (incr == exponent + 3)
+		if (cnt_h <= BITS_PER_MP_LIMB - 4)
+		  {
+		    topval[0] = 0;
+		    topval[1] = 10 << (BITS_PER_MP_LIMB - 4 - cnt_h);
+		  }
+		else
+		  {
+		    topval[0] = 10 << (BITS_PER_MP_LIMB - 4);
+		    topval[1] = 0;
+		    (void) __mpn_lshift (topval, topval, 2,
+					 BITS_PER_MP_LIMB - cnt_h);
+		  }
+
+	      /* We have to be careful when multiplying the last factor.
+		 If the result is greater than 1.0 be have to test it
+		 against 10.0.  If it is greater or equal to 10.0 the
+		 multiplication was not valid.  This is because we cannot
+		 determine the number of bits in the result in advance.  */
+	      if (incr < exponent + 3
+		  || (incr == exponent + 3 &&
+		      (tmp[tmpsize - 1] < topval[1]
+		       || (tmp[tmpsize - 1] == topval[1]
+			   && tmp[tmpsize - 2] < topval[0]))))
+		{
+		  /* The factor is right.  Adapt binary and decimal
+		     exponents.	 */ 
+		  exponent -= incr;
+		  exp10 |= 1 << explog;
+
+		  /* If this factor yields a number greater or equal to
+		     1.0, we must not shift the non-fractional digits down. */
+		  if (exponent < 0)
+		    cnt_h += -exponent;
+
+		  /* Now we optimize the number representation.	 */
+		  for (i = 0; tmp[i] == 0; ++i);
+		  if (cnt_h == BITS_PER_MP_LIMB - 1)
+		    {
+		      MPN_COPY (frac, tmp + i, tmpsize - i);
+		      fracsize = tmpsize - i;
+		    }
+		  else
+		    {
+		      count_trailing_zeros (cnt_l, tmp[i]);
+
+		      /* Now shift the numbers to their optimal position.  */
+		      if (i == 0 && BITS_PER_MP_LIMB - 1 - cnt_h > cnt_l)
+			{
+			  /* We cannot save any memory.	 Just roll the
+			     number so that the leading digit is in a
+			     seperate limb.  */
+
+			  cy = __mpn_lshift (frac, tmp, tmpsize, cnt_h + 1);
+			  fracsize = tmpsize + 1;
+			  frac[fracsize - 1] = cy;
+			}
+		      else if (BITS_PER_MP_LIMB - 1 - cnt_h <= cnt_l)
+			{
+			  (void) __mpn_rshift (frac, tmp + i, tmpsize - i,
+					       BITS_PER_MP_LIMB - 1 - cnt_h);
+			  fracsize = tmpsize - i;
+			}
+		      else
+			{
+			  /* We can only save the memory of the limbs which
+			     are zero.	The non-zero parts occupy the same
+			     number of limbs.  */
+
+			  (void) __mpn_rshift (frac, tmp + (i - 1),
+					       tmpsize - (i - 1),
+					       BITS_PER_MP_LIMB - 1 - cnt_h);
+			  fracsize = tmpsize - (i - 1);
+			}
+		    }
+		  used_limbs = fracsize - 1;
+		}
+	    }
+	  --explog;
+	}
+      while (tens != &_fpioconst_pow10[1] && exponent > 0);
+      /* All factors but 10^-1 are tested now.	*/
+      if (exponent > 0)
+	{
+	  cy = __mpn_mul_1 (tmp, frac, fracsize, 10);
+	  tmpsize = fracsize;
+	  assert (cy == 0 || tmp[tmpsize - 1] < 20);
+
+	  (void) __mpn_rshift (frac, tmp, tmpsize, MIN (4, exponent));
+	  fracsize = tmpsize;
+	  exp10 |= 1;
+	  assert (frac[fracsize - 1] < 10);
+	}
+      exponent = exp10;
+    }
+  else
+    {
+      /* This is a special case.  We don't need a factor because the
+	 numbers are in the range of 0.0 <= fp < 8.0.  We simply
+	 shift it to the right place and divide it by 1.0 to get the
+	 leading digit.	 (Of course this division is not really made.)	*/
+      assert (0 <= exponent && exponent < 3 &&
+	      exponent + to_shift < BITS_PER_MP_LIMB);
+
+      /* Now shift the input value to its right place.	*/
+      cy = __mpn_lshift (frac, fp_input, fracsize, (exponent + to_shift));
+      frac[fracsize++] = cy; 
+      exponent = 0;
+    }
+
+  {
+    int width = info->width;
+    char *buffer, *startp, *cp;
+    int chars_needed;
+    int expscale;
+    int intdig_max, intdig_no = 0;
+    int fracdig_min, fracdig_max, fracdig_no = 0;
+    int dig_max;
+    int significant;
+
+    if (tolower (info->spec) == 'e')
+      {
+	type = info->spec;
+	intdig_max = 1;
+	fracdig_min = fracdig_max = info->prec < 0 ? 6 : info->prec;
+	chars_needed = 1 + 1 + fracdig_max + 1 + 1 + 4;
+	/*	       d   .	 ddd	     e	 +-  ddd  */
+	dig_max = INT_MAX;		/* Unlimited.  */
+	significant = 1;		/* Does not matter here.  */
+      }
+    else if (info->spec == 'f')
+      {
+	type = 'f';
+	fracdig_min = fracdig_max = info->prec < 0 ? 6 : info->prec;
+	if (expsign == 0)
+	  {
+	    intdig_max = exponent + 1;
+	    /* This can be really big!	*/  /* XXX Maybe malloc if too big? */
+	    chars_needed = exponent + 1 + 1 + fracdig_max;
+	  }
+	else
+	  {
+	    intdig_max = 1;
+	    chars_needed = 1 + 1 + fracdig_max;
+	  }
+	dig_max = INT_MAX;		/* Unlimited.  */
+	significant = 1;		/* Does not matter here.  */
+      }
+    else
+      {
+	dig_max = info->prec < 0 ? 6 : (info->prec == 0 ? 1 : info->prec);
+	if ((expsign == 0 && exponent >= dig_max)
+	    || (expsign != 0 && exponent > 4))
+	  {
+	    type = isupper (info->spec) ? 'E' : 'e';
+	    fracdig_max = dig_max - 1;
+	    intdig_max = 1;
+	    chars_needed = 1 + 1 + fracdig_max + 1 + 1 + 4;
+	  }
+	else
+	  {
+	    type = 'f';
+	    intdig_max = expsign == 0 ? exponent + 1 : 0;
+	    fracdig_max = dig_max - intdig_max;
+	    /* We need space for the significant digits and perhaps for
+	       leading zeros when < 1.0.  Pessimistic guess: dig_max.  */
+	    chars_needed = dig_max + dig_max + 1;
+	  }
+	fracdig_min = info->alt ? fracdig_max : 0;
+	significant = 0;		/* We count significant digits.	 */
+      }
+
+    if (grouping)
+      /* Guess the number of groups we will make, and thus how
+	 many spaces we need for separator characters.  */
+      chars_needed += guess_grouping (intdig_max, grouping, thousands_sep);
+
+    /* Allocate buffer for output.  We need two more because while rounding
+       it is possible that we need two more characters in front of all the
+       other output.  */
+    buffer = alloca (2 + chars_needed);
+    cp = startp = buffer + 2;	/* Let room for rounding.  */ 
+
+    /* Do the real work: put digits in allocated buffer.  */
+    if (expsign == 0 || type != 'f')
+      {
+	assert (expsign == 0 || intdig_max == 1);
+	while (intdig_no < intdig_max)
+	  {
+	    ++intdig_no;
+	    *cp++ = hack_digit ();
+	  }
+	significant = 1;
+	if (info->alt
+	    || fracdig_min > 0
+	    || (fracdig_max > 0 && (fracsize > 1 || frac[0] != 0)))
+	  *cp++ = decimal;
+      }
+    else
+      {
+	/* |fp| < 1.0 and the selected type is 'f', so put "0."
+	   in the buffer.  */
+	*cp++ = '0';
+	--exponent;
+	*cp++ = decimal;
+      }
+
+    /* Generate the needed number of fractional digits.	 */
+    while (fracdig_no < fracdig_min
+	   || (fracdig_no < fracdig_max && (fracsize > 1 || frac[0] != 0)))
+      {
+	++fracdig_no;
+	*cp = hack_digit ();
+	if (*cp != '0')
+	  significant = 1;
+	else if (significant == 0)
+	  {
+	    ++fracdig_max;
+	    if (fracdig_min > 0)
+	      ++fracdig_min;
+	  }
+	++cp;
+      }
+
+    /* Do rounding.  */
+    digit = hack_digit ();
+    if (digit > '4')
+      {
+	char *tp = cp;
+
+	if (digit == '5')
+	  /* This is the critical case.	 */
+	  if (fracsize == 1 && frac[0] == 0)
+	    /* Rest of the number is zero -> round to even.
+	       (IEEE 754-1985 4.1 says this is the default rounding.)  */
+	    if ((*(cp - 1) & 1) == 0)
+	      goto do_expo;
+
+	if (fracdig_no > 0)
+	  {
+	    /* Process fractional digits.  Terminate if not rounded or
+	       radix character is reached.  */
+	    while (*--tp != decimal && *tp == '9')
+	      *tp = '0';
+	    if (*tp != decimal)
+	      /* Round up.  */
+	      (*tp)++;
+	  }
+
+	if (fracdig_no == 0 || *tp == decimal)
+	  {
+	    /* Round the integer digits.  */
+	    if (*(tp - 1) == decimal)
+	      --tp;
+
+	    while (--tp >= startp && *tp == '9')
+	      *tp = '0';
+
+	    if (tp >= startp)
+	      /* Round up.  */
+	      (*tp)++;
+	    else
+	      /* It is more citical.  All digits were 9's.  */
+	      {
+		if (type != 'f')
+		  {
+		    *startp = '1';
+		    exponent += expsign == 0 ? 1 : -1;
+		  }
+		else if (intdig_no == dig_max)
+		  {
+		    /* This is the case where for type %g the number fits
+		       really in the range for %f output but after rounding
+		       the number of digits is too big.	 */
+		    *--startp = decimal;
+		    *--startp = '1';
+
+		    if (info->alt || fracdig_no > 0)
+		      {
+			/* Overwrite the old radix character.  */
+			startp[intdig_no + 2] = '0';
+			++fracdig_no;
+		      }
+
+		    fracdig_no += intdig_no;
+		    intdig_no = 1;
+		    fracdig_max = intdig_max - intdig_no;
+		    ++exponent;
+		    /* Now we must print the exponent.	*/
+		    type = isupper (info->spec) ? 'E' : 'e';
+		  }
+		else
+		  {
+		    /* We can simply add another another digit before the
+		       radix.  */
+		    *--startp = '1';
+		    ++intdig_no;
+		  }
+
+		/* While rounding the number of digits can change.
+		   If the number now exceeds the limits remove some
+		   fractional digits.  */
+		if (intdig_no + fracdig_no > dig_max)
+		  {
+		    cp -= intdig_no + fracdig_no - dig_max;
+		    fracdig_no -= intdig_no + fracdig_no - dig_max;
+		  }
+	      }
+	  }
+      }
+
+  do_expo:
+    /* Now remove unnecessary '0' at the end of the string.  */
+    while (fracdig_no > fracdig_min && *(cp - 1) == '0')
+      {
+	--cp;
+	--fracdig_no;
+      }
+    /* If we eliminate all fractional digits we perhaps also can remove
+       the radix character.  */
+    if (fracdig_no == 0 && !info->alt && *(cp - 1) == decimal)
+      --cp;
+
+    if (grouping)
+      /* Add in separator characters, overwriting the same buffer.  */
+      cp = group_number (startp, cp, intdig_no, grouping, thousands_sep);
+
+    /* Write the exponent if it is needed.  */
+    if (type != 'f')
+      {
+	*cp++ = type;
+	*cp++ = expsign ? '-' : '+';
+
+	/* Find the magnitude of the exponent.	*/
+	expscale = 10;
+	while (expscale <= exponent)
+	  expscale *= 10;
+
+	if (exponent < 10)
+	  /* Exponent always has at least two digits.  */
+	  *cp++ = '0';
+	else
+	  do
+	    {
+	      expscale /= 10;
+	      *cp++ = '0' + (exponent / expscale);
+	      exponent %= expscale;
+	    }
+	  while (expscale > 10);
+	*cp++ = '0' + exponent;
+      }
+
+    /* Compute number of characters which must be filled with the padding
+       character.  */ 
+    if (is_neg || info->showsign || info->space)
+      --width;
+    width -= cp - startp;
+
+    if (!info->left && info->pad != '0' && width > 0)
+      PADN (info->pad, width);
+
+    if (is_neg)
+      outchar ('-');
+    else if (info->showsign)
+      outchar ('+');
+    else if (info->space)
+      outchar (' ');
+
+    if (!info->left && info->pad == '0' && width > 0)
+      PADN ('0', width);
+
+    PRINT (startp, cp - startp);
+
+    if (info->left && width > 0)
+      PADN (info->pad, width);
+  }
+  return done;
+}
+
+/* Return the number of extra grouping characters that will be inserted
+   into a number with INTDIG_MAX integer digits.  */
+
+static unsigned int
+guess_grouping (unsigned int intdig_max, const char *grouping, wchar_t sepchar)
+{
+  unsigned int groups;
+
+  /* We treat all negative values like CHAR_MAX.  */
+
+  if (*grouping == CHAR_MAX || *grouping <= 0)
+    /* No grouping should be done.  */
+    return 0;
+
+  groups = 0;
+  while (intdig_max > (unsigned int) *grouping)
+    {
+      ++groups;
+      intdig_max -= *grouping++;
+
+      if (*grouping == CHAR_MAX || *grouping < 0)
+	/* No more grouping should be done.  */
+	break;
+      else if (*grouping == 0)
+	{
+	  /* Same grouping repeats.  */
+	  groups += intdig_max / grouping[-1];
+	  break;
+	}
+    }
+
+  return groups;
+}
+
+/* Group the INTDIG_NO integer digits of the number in [BUF,BUFEND).
+   There is guaranteed enough space past BUFEND to extend it.
+   Return the new end of buffer.  */
+
+static char *
+group_number (char *buf, char *bufend, unsigned int intdig_no,
+	      const char *grouping, wchar_t thousands_sep)
+{
+  unsigned int groups = guess_grouping (intdig_no, grouping, thousands_sep);
+  char *p;
+
+  if (groups == 0)
+    return bufend;
+
+  /* Move the fractional part down.  */
+  memmove (buf + intdig_no + groups, buf + intdig_no,
+	   bufend - (buf + intdig_no));
+
+  p = buf + intdig_no + groups - 1;
+  do
+    {
+      unsigned int len = *grouping++;
+      do
+	*p-- = buf[--intdig_no];
+      while (--len > 0);
+      *p-- = thousands_sep;
+
+      if (*grouping == CHAR_MAX || *grouping < 0)
+	/* No more grouping should be done.  */
+	break;
+      else if (*grouping == 0)
+	/* Same grouping repeats.  */
+	--grouping;
+    } while (intdig_no > (unsigned int) *grouping);
+
+  /* Copy the remaining ungrouped digits.  */
+  do
+    *p-- = buf[--intdig_no];
+  while (p > buf);
+
+  return bufend + groups;
+}
diff --git a/stdio-common/psignal.c b/stdio-common/psignal.c
new file mode 100644
index 0000000000..8997a2ecdf
--- /dev/null
+++ b/stdio-common/psignal.c
@@ -0,0 +1,49 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <stdio.h>
+#include <signal.h>
+
+
+#ifndef	HAVE_GNU_LD
+#define	_sys_siglist	sys_siglist
+#endif
+
+/* Defined in sys_siglist.c.  */
+extern CONST char *CONST _sys_siglist[];
+
+
+/* Print out on stderr a line consisting of the test in S, a colon, a space,
+   a message describing the meaning of the signal number SIG and a newline.
+   If S is NULL or "", the colon and space are omitted.  */
+void
+DEFUN(psignal, (sig, s), int sig AND register CONST char *s)
+{
+  CONST char *colon;
+
+  if (s == NULL || s == '\0')
+    s = colon = "";
+  else
+    colon = ": ";
+
+  if (sig >= 0 && sig < NSIG)
+    (void) fprintf(stderr, "%s%s%s\n", s, colon, _sys_siglist[sig]);
+  else
+    (void) fprintf(stderr, "%s%sUnknown signal %d\n", s, colon, sig);
+}
diff --git a/stdio-common/putw.c b/stdio-common/putw.c
new file mode 100644
index 0000000000..1b70baeeaf
--- /dev/null
+++ b/stdio-common/putw.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 1991 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <stdio.h>
+
+
+/* Write the word (int) W to STREAM.  */
+int
+DEFUN(putw, (w, stream), int w AND FILE *stream)
+{
+  /* Is there a better way?  */
+  if (fwrite((CONST PTR) &w, sizeof(w), 1, stream) < 1)
+    return(EOF);
+  return(0);
+}
diff --git a/stdio-common/reg-printf.c b/stdio-common/reg-printf.c
new file mode 100644
index 0000000000..95d7a1f3c9
--- /dev/null
+++ b/stdio-common/reg-printf.c
@@ -0,0 +1,47 @@
+/* Copyright (C) 1991 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <errno.h>
+#include <limits.h>
+#include <printf.h>
+
+/* Array of functions indexed by format character.  */
+static printf_function *printf_funcs[UCHAR_MAX + 1];
+printf_arginfo_function *__printf_arginfo_table[UCHAR_MAX + 1];
+
+printf_function **__printf_function_table;
+
+/* Register FUNC to be called to format SPEC specifiers.  */
+int
+DEFUN(register_printf_function, (spec, converter, arginfo),
+      int spec AND printf_function converter AND
+      printf_arginfo_function arginfo)
+{
+  if (spec < 0 || spec > (int) UCHAR_MAX)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  __printf_function_table = printf_funcs;
+  __printf_arginfo_table[spec] = arginfo;
+  printf_funcs[spec] = converter;
+
+  return 0;
+}
diff --git a/stdio-common/scanf.c b/stdio-common/scanf.c
new file mode 100644
index 0000000000..cf43363958
--- /dev/null
+++ b/stdio-common/scanf.c
@@ -0,0 +1,40 @@
+/* Copyright (C) 1991, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifdef USE_IN_LIBIO
+# define vscanf _IO_vscanf
+#endif
+
+/* Read formatted input from stdin according to the format string FORMAT.  */
+/* VARARGS1 */
+int
+scanf (format)
+     const char *format;
+{
+  va_list arg;
+  int done;
+
+  va_start (arg, format);
+  done = vscanf (format, arg);
+  va_end (arg);
+
+  return done;
+}
diff --git a/stdio-common/snprintf.c b/stdio-common/snprintf.c
new file mode 100644
index 0000000000..00b85f3175
--- /dev/null
+++ b/stdio-common/snprintf.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 1991, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifdef USE_IN_LIBIO
+# define vsnprintf _IO_vsnprintf
+#endif
+
+/* Write formatted output into S, according to the format
+   string FORMAT, writing no more than MAXLEN characters.  */
+/* VARARGS3 */
+int
+snprintf (s, maxlen, format)
+      char *s;
+      size_t maxlen;
+      const char *format;
+{
+  va_list arg;
+  int done;
+
+  va_start (arg, format);
+  done = vsnprintf (s, maxlen, format, arg);
+  va_end (arg);
+
+  return done;
+}
diff --git a/stdio-common/sprintf.c b/stdio-common/sprintf.c
new file mode 100644
index 0000000000..9cfc89cb84
--- /dev/null
+++ b/stdio-common/sprintf.c
@@ -0,0 +1,41 @@
+/* Copyright (C) 1991, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifdef USE_IN_LIBIO
+# define vsprintf _IO_vsprintf
+#endif
+
+/* Write formatted output into S, according to the format string FORMAT.  */
+/* VARARGS2 */
+int
+sprintf (s, format)
+     char *s;
+     const char *format;
+{
+  va_list arg;
+  int done;
+
+  va_start (arg, format);
+  done = vsprintf (s, format, arg);
+  va_end (arg);
+
+  return done;
+}
diff --git a/stdio-common/sscanf.c b/stdio-common/sscanf.c
new file mode 100644
index 0000000000..794a3ce628
--- /dev/null
+++ b/stdio-common/sscanf.c
@@ -0,0 +1,41 @@
+/* Copyright (C) 1991, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifdef USE_IN_LIBIO
+# define __vsscanf _IO_vsscanf
+#endif
+
+/* Read formatted input from S, according to the format string FORMAT.  */
+/* VARARGS2 */
+int
+sscanf (s, format)
+     const char *s;
+     const char *format;
+{
+  va_list arg;
+  int done;
+
+  va_start (arg, format);
+  done = __vsscanf (s, format, arg);
+  va_end (arg);
+
+  return done;
+}
diff --git a/stdio-common/tempnam.c b/stdio-common/tempnam.c
new file mode 100644
index 0000000000..14988a8656
--- /dev/null
+++ b/stdio-common/tempnam.c
@@ -0,0 +1,50 @@
+/* Copyright (C) 1991, 1993 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/* Generate a unique temporary filename using up to five characters of PFX
+   if it is not NULL.  The directory to put this file in is searched for
+   as follows: First the environment variable "TMPDIR" is checked.
+   If it contains the name of a writable directory, that directory is used.
+   If not and if DIR is not NULL, that value is checked.  If that fails,
+   P_tmpdir is tried and finally "/tmp".  The storage for the filename
+   is allocated by `malloc'.  */
+char *
+DEFUN(tempnam, (dir, pfx), CONST char *dir AND CONST char *pfx)
+{
+  size_t len;
+  register char *s;
+  register char *t = __stdio_gen_tempname(dir, pfx, 1, &len, (FILE **) NULL);
+
+  if (t == NULL)
+    return NULL;
+
+  s = (char *) malloc(len);
+  if (s == NULL)
+    return NULL;
+
+  (void) memcpy(s, t, len);
+  return s;
+}
diff --git a/stdio-common/temptest.c b/stdio-common/temptest.c
new file mode 100644
index 0000000000..374719896a
--- /dev/null
+++ b/stdio-common/temptest.c
@@ -0,0 +1,31 @@
+#include <ansidecl.h>
+#include <stdio.h>
+#include <string.h>
+
+char *files[500];
+
+int
+main ()
+{
+  char *fn;
+  FILE *fp;
+  int i;
+
+  for (i = 0; i < 500; i++) {
+    fn = __stdio_gen_tempname((CONST char *) NULL,
+	"file", 0, (size_t *) NULL, (FILE **) NULL);
+    if (fn == NULL) {
+      printf ("__stdio_gen_tempname failed\n");
+      exit (1);
+    }
+    files[i] = strdup (fn);
+    printf ("file: %s\n", fn);
+    fp = fopen (fn, "w");
+    fclose (fp);
+  }
+
+  for (i = 0; i < 500; i++)
+    remove (files[i]);
+
+  exit (0);
+}
diff --git a/stdio-common/test-fseek.c b/stdio-common/test-fseek.c
new file mode 100644
index 0000000000..d56c669a54
--- /dev/null
+++ b/stdio-common/test-fseek.c
@@ -0,0 +1,67 @@
+#include <ansidecl.h>
+#include <stdio.h>
+
+#define TESTFILE "/tmp/test.dat"
+
+int
+main __P((void))
+{
+  FILE *fp;
+  int i, j;
+
+  puts ("\nFile seek test");
+  fp = fopen (TESTFILE, "w");
+  if (fp == NULL)
+    {
+      perror (TESTFILE);
+      return 1;
+    }
+
+  for (i = 0; i < 256; i++)
+    putc (i, fp);
+  if (freopen (TESTFILE, "r", fp) != fp)
+    {
+      perror ("Cannot open file for reading");
+      return 1;
+    }
+
+  for (i = 1; i <= 255; i++)
+    {
+      printf ("%3d\n", i);
+      fseek (fp, (long) -i, SEEK_END);
+      if ((j = getc (fp)) != 256 - i)
+	{
+	  printf ("SEEK_END failed %d\n", j);
+	  break;
+	}
+      if (fseek (fp, (long) i, SEEK_SET))
+	{
+	  puts ("Cannot SEEK_SET");
+	  break;
+	}
+      if ((j = getc (fp)) != i)
+	{
+	  printf ("SEEK_SET failed %d\n", j);
+	  break;
+	}
+      if (fseek (fp, (long) i, SEEK_SET))
+	{
+	  puts ("Cannot SEEK_SET");
+	  break;
+	}
+      if (fseek (fp, (long) (i >= 128 ? -128 : 128), SEEK_CUR))
+	{
+	  puts ("Cannot SEEK_CUR");
+	  break;
+	}
+      if ((j = getc (fp)) != (i >= 128 ? i - 128 : i + 128))
+	{
+	  printf ("SEEK_CUR failed %d\n", j);
+	  break;
+	}
+    }
+  fclose (fp);
+
+  puts ((i > 255) ? "Test succeeded." : "Test FAILED!");
+  return (i > 255) ? 0 : 1;
+}
diff --git a/stdio-common/test-fwrite.c b/stdio-common/test-fwrite.c
new file mode 100644
index 0000000000..cc6cdf038e
--- /dev/null
+++ b/stdio-common/test-fwrite.c
@@ -0,0 +1,68 @@
+#include <stdio.h>
+#include <string.h>
+
+int
+main ()
+{
+  FILE *f = tmpfile ();
+  char obuf[99999], ibuf[sizeof obuf];
+  char *line;
+  size_t linesz;
+
+  if (! f)
+    {
+      perror ("tmpfile");
+      return 1;
+    }
+
+  if (fputs ("line\n", f) == EOF)
+    {
+      perror ("fputs");
+      return 1;
+    }
+
+  memset (obuf, 'z', sizeof obuf);
+  memset (ibuf, 'y', sizeof ibuf);
+  
+  if (fwrite (obuf, sizeof obuf, 1, f) != 1)
+    {
+      perror ("fwrite");
+      return 1;
+    }
+
+  rewind (f);
+
+  line = NULL;
+  linesz = 0;
+  if (getline (&line, &linesz, f) != 5)
+    {
+      perror ("getline");
+      return 1;
+    }
+  if (strcmp (line, "line\n"))
+    {
+      puts ("Lines differ.  Test FAILED!");
+      return 1;
+    }
+
+  if (fread (ibuf, sizeof ibuf, 1, f) != 1)
+    {
+      perror ("fread");
+      return 1;
+    }
+
+  if (memcmp (ibuf, obuf, sizeof ibuf))
+    {
+      puts ("Buffers differ.  Test FAILED!");
+      return 1;
+    }
+
+  asprintf (&line, "\
+GDB is free software and you are welcome to distribute copies of it\n\
+ under certain conditions; type \"show copying\" to see the conditions.\n\
+There is absolutely no warranty for GDB; type \"show warranty\" for details.\n\
+");
+
+  puts ("Test succeeded.");
+  return 0;
+}
diff --git a/stdio-common/test-popen.c b/stdio-common/test-popen.c
new file mode 100644
index 0000000000..b452f3f63c
--- /dev/null
+++ b/stdio-common/test-popen.c
@@ -0,0 +1,67 @@
+#include <ansidecl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+DEFUN(write_data, (stream), FILE *stream)
+{
+  int i;
+  for (i=0; i<100; i++)
+    fprintf (stream, "%d\n", i);
+  if (ferror (stream))  {
+    fprintf (stderr, "Output to stream failed.\n");
+    exit (1);
+    }
+}
+
+void
+DEFUN(read_data, (stream), FILE *stream)
+{
+  int i, j;
+
+  for (i=0; i<100; i++)
+    {
+      if (fscanf (stream, "%d\n", &j) != 1 || j != i)
+	{
+	  if (ferror (stream))
+	    perror ("fscanf");
+	  puts ("Test FAILED!");
+	  exit (1);
+	}
+    }
+}
+
+int
+DEFUN_VOID(main)
+{
+  FILE *output, *input;
+  int wstatus, rstatus;
+
+  output = popen ("/bin/cat >/tmp/tstpopen.tmp", "w");
+  if (output == NULL)
+    {
+      perror ("popen");
+      puts ("Test FAILED!");
+      exit (1);
+    }
+  write_data (output);
+  wstatus = pclose (output);
+  printf ("writing pclose returned %d\n", wstatus);
+  input = popen ("/bin/cat /tmp/tstpopen.tmp", "r");
+  if (input == NULL)
+    {
+      perror ("/tmp/tstpopen.tmp");
+      puts ("Test FAILED!");
+      exit (1);
+    }
+  read_data (input);
+  rstatus = pclose (input);
+  printf ("reading pclose returned %d\n", rstatus);
+
+  puts (wstatus | rstatus  ? "Test FAILED!" : "Test succeeded.");
+  exit (wstatus | rstatus);
+}
+
+  
+
+  
diff --git a/stdio-common/test_rdwr.c b/stdio-common/test_rdwr.c
new file mode 100644
index 0000000000..f987f16cd4
--- /dev/null
+++ b/stdio-common/test_rdwr.c
@@ -0,0 +1,130 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+int
+DEFUN(main, (argc, argv), int argc AND char **argv)
+{
+  static CONST char hello[] = "Hello, world.\n";
+  static CONST char replace[] = "Hewwo, world.\n";
+  static CONST size_t replace_from = 2, replace_to = 4;
+  char filename[FILENAME_MAX];
+  char *name = strrchr(*argv, '/');
+  char buf[BUFSIZ];
+  FILE *f;
+  int lose = 0;
+
+  if (name != NULL)
+    ++name;
+  else
+    name = *argv;
+
+  (void) sprintf(filename, "/tmp/%s.test", name);
+
+  f = fopen(filename, "w+");
+  if (f == NULL)
+    {
+      perror(filename);
+      exit(1);
+    }
+
+  (void) fputs(hello, f);
+  rewind(f);
+  (void) fgets(buf, sizeof(buf), f);
+  rewind(f);
+  (void) fputs(buf, f);
+  rewind(f);
+  {
+    register size_t i;
+    for (i = 0; i < replace_from; ++i)
+      {
+	int c = getc(f);
+	if (c == EOF)
+	  {
+	    printf("EOF at %u.\n", i);
+	    lose = 1;
+	    break;
+	  }
+	else if (c != hello[i])
+	  {
+	    printf("Got '%c' instead of '%c' at %u.\n",
+		   (unsigned char) c, hello[i], i);
+	    lose = 1;
+	    break;
+	  }
+      }
+  }
+
+  {
+    long int where = ftell(f);
+    if (where == replace_from)
+      {
+	register size_t i;
+	for (i = replace_from; i < replace_to; ++i)
+	  if (putc(replace[i], f) == EOF)
+	    {
+	      printf("putc('%c') got %s at %u.\n",
+		     replace[i], strerror(errno), i);
+	      lose = 1;
+	      break;
+	    }
+      }
+    else if (where == -1L)
+      {
+	printf("ftell got %s (should be at %u).\n",
+	       strerror(errno), replace_from);
+	lose = 1;
+      }
+    else
+      {
+	printf("ftell returns %u; should be %u.\n", where, replace_from);
+	lose = 1;
+      }
+  }
+
+  if (!lose)
+    {
+      rewind(f);
+      if (fgets(buf, sizeof(buf), f) == NULL)
+	{
+	  printf("fgets got %s.\n", strerror(errno));
+	  lose = 1;
+	}
+      else if (strcmp(buf, replace))
+	{
+	  printf("Read \"%s\" instead of \"%s\".\n", buf, replace);
+	  lose = 1;
+	}
+    }
+
+  if (lose)
+    printf("Test FAILED!  Losing file is \"%s\".\n", filename);
+  else
+    {
+      (void) remove(filename);
+      puts("Test succeeded.");
+    }
+
+  exit(lose ? EXIT_FAILURE : EXIT_SUCCESS);
+}
diff --git a/stdio-common/tmpfile.c b/stdio-common/tmpfile.c
new file mode 100644
index 0000000000..dfe11ada50
--- /dev/null
+++ b/stdio-common/tmpfile.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 1991, 1993 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <stdio.h>
+
+
+/* This returns a new stream opened on a temporary file (generated
+   by tmpnam) The file is opened with mode "w+b" (binary read/write).
+   If we couldn't generate a unique filename or the file couldn't
+   be opened, NULL is returned.  */
+FILE *
+DEFUN_VOID(tmpfile)
+{
+  char *filename;
+  FILE *f;
+
+  filename = __stdio_gen_tempname ((char *) NULL, "tmpf", 0,
+				   (size_t *) NULL, &f);
+  if (filename == NULL)
+    return NULL;
+
+  /* Note that this relies on the Unix semantics that
+     a file is not really removed until it is closed.  */
+  (void) remove (filename);
+
+  return f;
+}
diff --git a/stdio-common/tmpnam.c b/stdio-common/tmpnam.c
new file mode 100644
index 0000000000..88dd0a4ca5
--- /dev/null
+++ b/stdio-common/tmpnam.c
@@ -0,0 +1,42 @@
+/* Copyright (C) 1991, 1993 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+
+/* Generate a unique filename in P_tmpdir.  */
+char *
+DEFUN(tmpnam, (s), register char *s)
+{
+  register char *t = __stdio_gen_tempname((CONST char *) NULL,
+					  (CONST char *) NULL, 0,
+					  (size_t *) NULL, (FILE **) NULL);
+
+  if (t == NULL)
+    return NULL;
+
+  if (s != NULL)
+    (void) strcpy(s, t);
+  else
+    s = t;
+
+  return s;
+}
diff --git a/stdio-common/tst-fileno.c b/stdio-common/tst-fileno.c
new file mode 100644
index 0000000000..81945f7b44
--- /dev/null
+++ b/stdio-common/tst-fileno.c
@@ -0,0 +1,37 @@
+/* Copyright (C) 1994 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static int
+DEFUN(check, (name, stream, fd), CONST char *name AND FILE *stream AND int fd)
+{
+  int sfd = fileno (stream);
+  printf ("(fileno (%s) = %d) %c= %d\n", name, sfd, sfd == fd ? '=' : '!', fd);
+  return sfd != fd;
+}
+
+int
+DEFUN_VOID(main)
+{
+  exit (check ("stdin", stdin, STDIN_FILENO) ||
+	check ("stdout", stdout, STDOUT_FILENO) ||
+	check ("stderr", stderr, STDERR_FILENO));
+}
diff --git a/stdio-common/tst-printf.c b/stdio-common/tst-printf.c
new file mode 100644
index 0000000000..c177da18b2
--- /dev/null
+++ b/stdio-common/tst-printf.c
@@ -0,0 +1,298 @@
+/* Copyright (C) 1991, 1992, 1993, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#ifdef	BSD
+#include </usr/include/stdio.h>
+#define EXIT_SUCCESS 0
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#include <float.h>
+
+
+void
+DEFUN(fmtchk, (fmt), CONST char *fmt)
+{
+  (void) fputs(fmt, stdout);
+  (void) printf(":\t`");
+  (void) printf(fmt, 0x12);
+  (void) printf("'\n");
+}
+
+void
+DEFUN(fmtst1chk, (fmt), CONST char *fmt)
+{
+  (void) fputs(fmt, stdout);
+  (void) printf(":\t`");
+  (void) printf(fmt, 4, 0x12);
+  (void) printf("'\n");
+}
+
+void
+DEFUN(fmtst2chk, (fmt), CONST char *fmt)
+{
+  (void) fputs(fmt, stdout);
+  (void) printf(":\t`");
+  (void) printf(fmt, 4, 4, 0x12);
+  (void) printf("'\n");
+}
+
+/* This page is covered by the following copyright: */
+
+/* (C) Copyright C E Chew
+ *
+ * Feel free to copy, use and distribute this software provided:
+ *
+ *	1. you do not pretend that you wrote it
+ *	2. you leave this copyright notice intact.
+ */
+
+/*
+ * Extracted from exercise.c for glibc-1.05 bug report by Bruce Evans.
+ */
+
+#define DEC -123
+#define INT 255
+#define UNS (~0)
+
+/* Formatted Output Test
+ *
+ * This exercises the output formatting code.
+ */
+
+void
+DEFUN_VOID(fp_test)
+{
+  int i, j, k, l;
+  char buf[7];
+  char *prefix = buf;
+  char tp[20];
+
+  puts("\nFormatted output test");
+  printf("prefix  6d      6o      6x      6X      6u\n");
+  strcpy(prefix, "%");
+  for (i = 0; i < 2; i++) {
+    for (j = 0; j < 2; j++) {
+      for (k = 0; k < 2; k++) {
+	for (l = 0; l < 2; l++) {
+	  strcpy(prefix, "%");
+	  if (i == 0) strcat(prefix, "-");
+	  if (j == 0) strcat(prefix, "+");
+	  if (k == 0) strcat(prefix, "#");
+	  if (l == 0) strcat(prefix, "0");
+	  printf("%5s |", prefix);
+	  strcpy(tp, prefix);
+	  strcat(tp, "6d |");
+	  printf(tp, DEC);
+	  strcpy(tp, prefix);
+	  strcat(tp, "6o |");
+	  printf(tp, INT);
+	  strcpy(tp, prefix);
+	  strcat(tp, "6x |");
+	  printf(tp, INT);
+	  strcpy(tp, prefix);
+	  strcat(tp, "6X |");
+	  printf(tp, INT);
+	  strcpy(tp, prefix);
+	  strcat(tp, "6u |");
+	  printf(tp, UNS);
+	  printf("\n");
+	}
+      }
+    }
+  }
+  printf("%10s\n", (char *) NULL);
+  printf("%-10s\n", (char *) NULL);
+}
+
+int
+DEFUN_VOID(main)
+{
+  static char shortstr[] = "Hi, Z.";
+  static char longstr[] = "Good morning, Doctor Chandra.  This is Hal.  \
+I am ready for my first lesson today.";
+
+  fmtchk("%.4x");
+  fmtchk("%04x");
+  fmtchk("%4.4x");
+  fmtchk("%04.4x");
+  fmtchk("%4.3x");
+  fmtchk("%04.3x");
+
+  fmtst1chk("%.*x");
+  fmtst1chk("%0*x");
+  fmtst2chk("%*.*x");
+  fmtst2chk("%0*.*x");
+
+#ifndef	BSD
+  printf("bad format:\t\"%z\"\n");
+  printf("nil pointer (padded):\t\"%10p\"\n", (PTR) NULL);
+#endif
+
+  printf("decimal negative:\t\"%d\"\n", -2345);
+  printf("octal negative:\t\"%o\"\n", -2345);
+  printf("hex negative:\t\"%x\"\n", -2345);
+  printf("long decimal number:\t\"%ld\"\n", -123456L);
+  printf("long octal negative:\t\"%lo\"\n", -2345L);
+  printf("long unsigned decimal number:\t\"%lu\"\n", -123456L);
+  printf("zero-padded LDN:\t\"%010ld\"\n", -123456L);
+  printf("left-adjusted ZLDN:\t\"%-010ld\"\n", -123456);
+  printf("space-padded LDN:\t\"%10ld\"\n", -123456L);
+  printf("left-adjusted SLDN:\t\"%-10ld\"\n", -123456L);
+
+  printf("zero-padded string:\t\"%010s\"\n", shortstr);
+  printf("left-adjusted Z string:\t\"%-010s\"\n", shortstr);
+  printf("space-padded string:\t\"%10s\"\n", shortstr);
+  printf("left-adjusted S string:\t\"%-10s\"\n", shortstr);
+  printf("null string:\t\"%s\"\n", (char *)NULL);
+  printf("limited string:\t\"%.22s\"\n", longstr);
+
+  printf("e-style >= 1:\t\"%e\"\n", 12.34);
+  printf("e-style >= .1:\t\"%e\"\n", 0.1234);
+  printf("e-style < .1:\t\"%e\"\n", 0.001234);
+  printf("e-style big:\t\"%.60e\"\n", 1e20);
+  printf ("e-style == .1:\t\"%e\"\n", 0.1);
+  printf("f-style >= 1:\t\"%f\"\n", 12.34);
+  printf("f-style >= .1:\t\"%f\"\n", 0.1234);
+  printf("f-style < .1:\t\"%f\"\n", 0.001234);
+  printf("g-style >= 1:\t\"%g\"\n", 12.34);
+  printf("g-style >= .1:\t\"%g\"\n", 0.1234);
+  printf("g-style < .1:\t\"%g\"\n", 0.001234);
+  printf("g-style big:\t\"%.60g\"\n", 1e20);
+
+  printf (" %6.5f\n", .099999999860301614);
+  printf (" %6.5f\n", .1);
+  printf ("x%5.4fx\n", .5);
+
+  printf ("%#03x\n", 1);
+
+  {
+    double d = FLT_MIN;
+    int niter = 17;
+    
+    while (niter-- != 0)
+      printf ("%.17e\n", d / 2);
+    fflush (stdout);
+  }
+
+  printf ("%15.5e\n", 4.9406564584124654e-324);
+
+#define FORMAT "|%12.4f|%12.4e|%12.4g|\n"
+  printf (FORMAT, 0.0, 0.0, 0.0);
+  printf (FORMAT, 1.0, 1.0, 1.0);
+  printf (FORMAT, -1.0, -1.0, -1.0);
+  printf (FORMAT, 100.0, 100.0, 100.0);
+  printf (FORMAT, 1000.0, 1000.0, 1000.0);
+  printf (FORMAT, 10000.0, 10000.0, 10000.0);
+  printf (FORMAT, 12345.0, 12345.0, 12345.0);
+  printf (FORMAT, 100000.0, 100000.0, 100000.0);
+  printf (FORMAT, 123456.0, 123456.0, 123456.0);
+#undef	FORMAT
+
+  {
+    char buf[20];
+    printf ("snprintf (\"%%30s\", \"foo\") == %d, \"%.*s\"\n",
+	    snprintf (buf, sizeof (buf), "%30s", "foo"), sizeof (buf), buf);
+  }
+
+  fp_test ();
+
+  printf ("%e should be 1.234568e+06\n", 1234567.8);
+  printf ("%f should be 1234567.800000\n", 1234567.8);
+  printf ("%g should be 1.23457e+06\n", 1234567.8);
+  printf ("%g should be 123.456\n", 123.456);
+  printf ("%g should be 1e+06\n", 1000000.0);
+  printf ("%g should be 10\n", 10.0);
+  printf ("%g should be 0.02\n", 0.02);
+
+  {
+    double x=1.0;
+    printf("%.17f\n",(1.0/x/10.0+1.0)*x-x);
+  }
+
+  puts ("--- Should be no further output. ---");
+  rfg1 ();
+  rfg2 ();
+
+  exit(EXIT_SUCCESS);
+}
+
+rfg1 ()
+{
+  char buf[100];
+
+  sprintf (buf, "%5.s", "xyz");
+  if (strcmp (buf, "     ") != 0)
+    printf ("got: '%s', expected: '%s'\n", buf, "     ");
+  sprintf (buf, "%5.f", 33.3);
+  if (strcmp (buf, "   33") != 0)
+    printf ("got: '%s', expected: '%s'\n", buf, "   33");
+  sprintf (buf, "%8.e", 33.3e7);
+  if (strcmp (buf, "   3e+08") != 0)
+    printf ("got: '%s', expected: '%s'\n", buf, "   3e+08");
+  sprintf (buf, "%8.E", 33.3e7);
+  if (strcmp (buf, "   3E+08") != 0)
+    printf ("got: '%s', expected: '%s'\n", buf, "   3E+08");
+  sprintf (buf, "%.g", 33.3);
+  if (strcmp (buf, "3e+01") != 0)
+    printf ("got: '%s', expected: '%s'\n", buf, "3e+01");
+  sprintf (buf, "%.G", 33.3);
+  if (strcmp (buf, "3E+01") != 0)
+    printf ("got: '%s', expected: '%s'\n", buf, "3E+01");
+  return 0;
+}
+
+rfg2 ()
+{
+  int prec;
+  char buf[100];
+
+  prec = 0;
+  sprintf (buf, "%.*g", prec, 3.3);
+  if (strcmp (buf, "3") != 0)
+    printf ("got: '%s', expected: '%s'\n", buf, "3");
+  prec = 0;
+  sprintf (buf, "%.*G", prec, 3.3);
+  if (strcmp (buf, "3") != 0)
+    printf ("got: '%s', expected: '%s'\n", buf, "3");
+  prec = 0;
+  sprintf (buf, "%7.*G", prec, 3.33);
+  if (strcmp (buf, "      3") != 0)
+    printf ("got: '%s', expected: '%s'\n", buf, "      3");
+  prec = 3;
+  sprintf (buf, "%04.*o", prec, 33);
+  if (strcmp (buf, " 041") != 0)
+    printf ("got: '%s', expected: '%s'\n", buf, " 041");
+  prec = 7;
+  sprintf (buf, "%09.*u", prec, 33);
+  if (strcmp (buf, "  0000033") != 0)
+    printf ("got: '%s', expected: '%s'\n", buf, "  0000033");
+  prec = 3;
+  sprintf (buf, "%04.*x", prec, 33);
+  if (strcmp (buf, " 021") != 0)
+    printf ("got: '%s', expected: '%s'\n", buf, " 021");
+  prec = 3;
+  sprintf (buf, "%04.*X", prec, 33);
+  if (strcmp (buf, " 021") != 0)
+    printf ("got: '%s', expected: '%s'\n", buf, " 021");
+  return 0;
+}
diff --git a/stdio-common/tstgetln.c b/stdio-common/tstgetln.c
new file mode 100644
index 0000000000..ea8ea817da
--- /dev/null
+++ b/stdio-common/tstgetln.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <stdio.h>
+
+int
+DEFUN_VOID(main)
+{
+  char *buf = NULL;
+  size_t size = 0;
+  ssize_t len;
+
+  while ((len = getline (&buf, &size, stdin)) != -1)
+    {
+      printf ("bufsize %u; read %d: ", size, len);
+      if (fwrite (buf, len, 1, stdout) != 1)
+	{
+	  perror ("fwrite");
+	  return 1;
+	}
+    }
+
+  if (ferror (stdin))
+    {
+      perror ("getline");
+      return 1;
+    }
+
+  return 0;
+}
diff --git a/stdio-common/tstgetln.input b/stdio-common/tstgetln.input
new file mode 100644
index 0000000000..d04ed5bf78
--- /dev/null
+++ b/stdio-common/tstgetln.input
@@ -0,0 +1,3 @@
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
+z
diff --git a/stdio-common/tstscanf.c b/stdio-common/tstscanf.c
new file mode 100644
index 0000000000..53d4b0ac47
--- /dev/null
+++ b/stdio-common/tstscanf.c
@@ -0,0 +1,100 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#ifdef	BSD
+#include </usr/include/stdio.h>
+#else
+#include <stdio.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+
+int
+DEFUN(main, (argc, argv), int argc AND char **argv)
+{
+  char buf[BUFSIZ];
+  FILE *in = stdin, *out = stdout;
+
+  if (argc == 2 && !strcmp (argv[1], "-opipe"))
+    {
+      out = popen ("/bin/cat", "w");
+      if (out == NULL)
+	{
+	  perror ("popen: /bin/cat");
+	  exit (EXIT_FAILURE);
+	}
+    }
+  else if (argc == 3 && !strcmp (argv[1], "-ipipe"))
+    {
+      sprintf (buf, "/bin/cat %s", argv[2]);
+      in = popen (buf, "r");
+    }
+
+  {
+    char name[50];
+    fprintf (out,
+	     "sscanf (\"thompson\", \"%%s\", name) == %d, name == \"%s\"\n",
+	     sscanf ("thompson", "%s", name),
+	     name);
+  }
+
+  fputs ("Testing scanf (vfscanf)\n", out);
+
+  fputs ("Test 1:\n", out);
+  {
+    int n, i;
+    float x;
+    char name[50];
+    n = fscanf (in, "%d%f%s", &i, &x, name);
+    fprintf (out, "n = %d, i = %d, x = %f, name = \"%.50s\"\n",
+	     n, i, x, name);
+  }
+  fprintf (out, "Residual: \"%s\"\n", fgets (buf, sizeof (buf), in));
+  fputs ("Test 2:\n", out);
+  {
+    int i;
+    float x;
+    char name[50];
+    (void) fscanf (in, "%2d%f%*d %[0123456789]", &i, &x, name);
+    fprintf (out, "i = %d, x = %f, name = \"%.50s\"\n", i, x, name);
+  }
+  fprintf (out, "Residual: \"%s\"\n", fgets (buf, sizeof (buf), in));
+  fputs ("Test 3:\n", out);
+  {
+    float quant;
+    char units[21], item[21];
+    while (!feof (in) && !ferror (in))
+      {
+	int count;
+	quant = 0.0;
+	units[0] = item[0] = '\0';
+	count = fscanf (in, "%f%20s of %20s", &quant, units, item);
+	(void) fscanf (in, "%*[^\n]");
+	fprintf (out, "count = %d, quant = %f, item = %.21s, units = %.21s\n",
+		 count, quant, item, units);
+      }
+  }
+  fprintf (out, "Residual: \"%s\"\n", fgets (buf, sizeof (buf), in));
+
+  if (out != stdout)
+    pclose (out);
+
+  exit(EXIT_SUCCESS);
+}
diff --git a/stdio-common/tstscanf.input b/stdio-common/tstscanf.input
new file mode 100644
index 0000000000..26158652dd
--- /dev/null
+++ b/stdio-common/tstscanf.input
@@ -0,0 +1,7 @@
+25 54.32E-1 thompson
+56789 0123 56a72
+2 quarts of oil
+-12.8degrees Celsius
+lots of luck
+10.0LBS      of       fertilizer
+100ergs of energy
diff --git a/stdio-common/vasprintf.c b/stdio-common/vasprintf.c
new file mode 100644
index 0000000000..d2ad6b1da6
--- /dev/null
+++ b/stdio-common/vasprintf.c
@@ -0,0 +1,86 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+
+/* Enlarge STREAM's buffer.  */
+static void
+DEFUN(enlarge_buffer, (stream, c),
+      register FILE *stream AND int c)
+{
+  ptrdiff_t bufp_offset = stream->__bufp - stream->__buffer;
+  char *newbuf;
+
+  stream->__bufsize += 100;
+  newbuf = (char *) realloc ((PTR) stream->__buffer, stream->__bufsize);
+  if (newbuf == NULL)
+    {
+      free ((PTR) stream->__buffer);
+      stream->__buffer = stream->__bufp
+	= stream->__put_limit = stream->__get_limit = NULL;
+      stream->__error = 1;
+    }
+  else
+    {
+      stream->__buffer = newbuf;
+      stream->__bufp = stream->__buffer + bufp_offset;
+      stream->__get_limit = stream->__put_limit;
+      stream->__put_limit = stream->__buffer + stream->__bufsize;
+      if (c != EOF)
+	*stream->__bufp++ = (unsigned char) c;
+    }
+}
+
+/* Write formatted output from FORMAT to a string which is
+   allocated with malloc and stored in *STRING_PTR.  */
+int
+DEFUN(vasprintf, (string_ptr, format, args),
+      char **string_ptr AND CONST char *format AND va_list args)
+{
+  FILE f;
+  int done;
+
+  memset ((PTR) &f, 0, sizeof (f));
+  f.__magic = _IOMAGIC;
+  f.__bufsize = 100;
+  f.__buffer = (char *) malloc (f.__bufsize);
+  if (f.__buffer == NULL)
+    return -1;
+  f.__bufp = f.__buffer;
+  f.__put_limit = f.__buffer + f.__bufsize;
+  f.__mode.__write = 1;
+  f.__room_funcs.__output = enlarge_buffer;
+  f.__seen = 1;
+
+  done = vfprintf (&f, format, args);
+  if (done < 0)
+    return done;
+
+  *string_ptr = realloc (f.__buffer, (f.__bufp - f.__buffer) + 1);
+  if (*string_ptr == NULL)
+    *string_ptr = f.__buffer;
+  (*string_ptr)[f.__bufp - f.__buffer] = '\0';
+  return done;
+}
diff --git a/stdio-common/vdprintf.c b/stdio-common/vdprintf.c
new file mode 100644
index 0000000000..9df4e537bc
--- /dev/null
+++ b/stdio-common/vdprintf.c
@@ -0,0 +1,51 @@
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+
+/* Write formatted output to file descriptor D according to the format string
+   FORMAT, using the argument list in ARG.  */
+int
+DEFUN(vdprintf, (d, format, arg),
+      int d AND CONST char *format AND va_list arg)
+{
+  int done;
+  FILE f;
+
+  /* Create an unbuffered stream talking to D on the stack.  */
+  memset ((PTR) &f, 0, sizeof(f));
+  f.__magic = _IOMAGIC;
+  f.__mode.__write = 1;
+  f.__cookie = (PTR) (long int) d; /* Casting to long quiets GCC on Alpha.  */
+  f.__room_funcs = __default_room_functions;
+  f.__io_funcs = __default_io_functions;
+  f.__seen = 1;
+  f.__userbuf = 1;
+
+  /* vfprintf will use a buffer on the stack for the life of the call,
+     and flush it when finished.  */
+  done = vfprintf (&f, format, arg);
+
+  return done;
+}
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
new file mode 100644
index 0000000000..63a5148463
--- /dev/null
+++ b/stdio-common/vfprintf.c
@@ -0,0 +1,858 @@
+/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ctype.h>
+#include <errno.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <printf.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <printf.h>
+#include <stddef.h>
+#include "_itoa.h"
+#include "../locale/localeinfo.h"
+
+/* Include the shared code for parsing the format string.  */
+#include "printf-parse.h"
+
+
+/* This function from the GNU C library is also used in libio.
+   To compile for use in libio, compile with -DUSE_IN_LIBIO.  */
+
+#ifdef USE_IN_LIBIO
+/* This code is for use in libio.  */
+#include <libioP.h>
+#define PUT(f, s, n)	_IO_sputn (f, s, n)
+#define PAD(padchar)							      \
+  if (specs[cnt].info.width > 0)					      \
+    done += _IO_padn (s, padchar, specs[cnt].info.width)
+#define PUTC(c, f)	_IO_putc (c, f)
+#define vfprintf	_IO_vfprintf
+#define size_t		_IO_size_t
+#define FILE		_IO_FILE
+#define va_list		_IO_va_list
+#undef	BUFSIZ
+#define BUFSIZ		_IO_BUFSIZ
+#define ARGCHECK(s, format)						      \
+  do									      \
+    {									      \
+      /* Check file argument for consistence.  */			      \
+      CHECK_FILE (s, -1);						      \
+      if (s->_flags & _IO_NO_WRITES || format == NULL)			      \
+	{								      \
+	  MAYBE_SET_EINVAL;						      \
+	  return -1;							      \
+	}								      \
+    } while (0)
+#define UNBUFFERED_P(s)	((s)->_IO_file_flags & _IO_UNBUFFERED)
+#else /* ! USE_IN_LIBIO */
+/* This code is for use in the GNU C library.  */
+#include <stdio.h>
+#define PUTC(c, f)	putc (c, f)
+#define PUT(f, s, n)	fwrite (s, 1, n, f)
+ssize_t __printf_pad __P ((FILE *, char pad, size_t n));
+#define PAD(padchar)							      \
+  if (specs[cnt].info.width > 0)					      \
+    { if (__printf_pad (s, padchar, specs[cnt].info.width) == -1)	      \
+	return -1; else done += specs[cnt].info.width; }
+#define ARGCHECK(s, format) \
+  do									      \
+    {									      \
+      /* Check file argument for consistence.  */			      \
+      if (!__validfp(s) || !s->__mode.__write || format == NULL)	      \
+	{								      \
+	  errno = EINVAL;						      \
+	  return -1;							      \
+	}								      \
+      if (!s->__seen)							      \
+	{								      \
+	  if (__flshfp (s, EOF) == EOF)					      \
+	    return -1;							      \
+	}								      \
+    } while (0)
+#define UNBUFFERED_P(s)	((s)->__buffer == NULL)
+#endif /* USE_IN_LIBIO */
+
+
+#define	outchar(x)							      \
+  do									      \
+    {									      \
+      register const int outc = (x);					      \
+      if (putc (outc, s) == EOF)					      \
+	return -1;							      \
+      else								      \
+	++done;								      \
+    } while (0)
+
+#define outstring(string, len)						      \
+  do									      \
+    {									      \
+      if (len > 20)							      \
+	{								      \
+	  if (PUT (s, string, len) != len)				      \
+	    return -1;							      \
+	  done += len;							      \
+	}								      \
+      else								      \
+	{								      \
+	  register const char *cp = string;				      \
+	  register int l = len;						      \
+	  while (l-- > 0)						      \
+	    outchar (*cp++);						      \
+	}								      \
+    } while (0)
+
+/* Helper function to provide temporary buffering for unbuffered streams.  */
+static int buffered_vfprintf __P ((FILE *stream, const char *fmt, va_list));
+
+static printf_function printf_unknown;
+
+extern printf_function **__printf_function_table;
+
+static char *group_number __P ((char *, char *, const char *, wchar_t));
+
+
+int
+vfprintf (s, format, ap)
+    register FILE *s;
+    const char *format;
+    va_list ap;
+{
+  /* The character used as thousands separator.  */
+  wchar_t thousands_sep;
+
+  /* The string describing the size of groups of digits.  */
+  const char *grouping;
+
+  /* Array with information about the needed arguments.  This has to be
+     dynamically extendable.  */
+  size_t nspecs;
+  size_t nspecs_max;
+  struct printf_spec *specs;
+
+  /* The number of arguments the format string requests.  This will
+     determine the size of the array needed to store the argument
+     attributes.  */
+  size_t nargs;
+  int *args_type;
+  union printf_arg *args_value;
+
+  /* Positional parameters refer to arguments directly.  This could also
+     determine the maximum number of arguments.  Track the maximum number.  */
+  size_t max_ref_arg;
+
+  /* End of leading constant string.  */
+  const char *lead_str_end;
+
+  /* Number of characters written.  */
+  register size_t done = 0;
+
+  /* Running pointer through format string.  */
+  const char *f;
+
+  /* Just a counter.  */
+  int cnt;
+
+  ARGCHECK (s, format);
+
+  if (UNBUFFERED_P (s))
+    /* Use a helper function which will allocate a local temporary buffer
+       for the stream and then call us again.  */
+    return buffered_vfprintf (s, format, ap);
+
+  /* Reset multibyte characters to their initial state.  */
+  (void) mblen ((char *) NULL, 0);
+
+  /* Figure out the thousands separator character.  */
+  if (mbtowc (&thousands_sep, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP),
+              strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0)
+    thousands_sep = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
+  grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
+  if (*grouping == '\0' || *grouping == CHAR_MAX || thousands_sep == L'\0')
+    grouping = NULL;
+
+  nspecs_max = 32;		/* A more or less arbitrary start value.  */
+  specs = alloca (nspecs_max * sizeof (struct printf_spec));
+  nspecs = 0;
+  nargs = 0;
+  max_ref_arg = 0;
+
+  /* Find the first format specifier.  */
+  lead_str_end = find_spec (format);
+
+  for (f = lead_str_end; *f != '\0'; f = specs[nspecs++].next_fmt)
+    {
+      if (nspecs >= nspecs_max)
+	{
+	  /* Extend the array of format specifiers.  */
+	  struct printf_spec *old = specs;
+
+	  nspecs_max *= 2;
+	  specs = alloca (nspecs_max * sizeof (struct printf_spec));
+	  if (specs == &old[nspecs])
+	    /* Stack grows up, OLD was the last thing allocated; extend it.  */
+	    nspecs_max += nspecs_max / 2;
+	  else
+	    {
+	      /* Copy the old array's elements to the new space.  */
+	      memcpy (specs, old, nspecs * sizeof (struct printf_spec));
+	      if (old == &specs[nspecs])
+		/* Stack grows down, OLD was just below the new SPECS.
+		   We can use that space when the new space runs out.  */
+		nspecs_max += nspecs_max / 2;
+	    }
+	}
+
+      /* Parse the format specifier.  */
+      nargs += parse_one_spec (f, nargs, &specs[nspecs], &max_ref_arg);
+    }
+
+  /* Determine the number of arguments the format string consumes.  */
+  nargs = MAX (nargs, max_ref_arg);
+
+  /* Allocate memory for the argument descriptions.  */
+  args_type = alloca (nargs * sizeof (int));
+  args_value = alloca (nargs * sizeof (union printf_arg));
+
+  /* XXX Could do sanity check here:
+     Initialize args_type elts to zero.
+     If any is still zero after this loop, format is invalid.  */
+
+  /* Fill in the types of all the arguments.  */
+  for (cnt = 0; cnt < nspecs; ++cnt)
+    {
+      /* If the width is determined by an argument this is an int.  */ 
+      if (specs[cnt].width_arg != -1)
+	args_type[specs[cnt].width_arg] = PA_INT;
+
+      /* If the precision is determined by an argument this is an int.  */ 
+      if (specs[cnt].prec_arg != -1)
+	args_type[specs[cnt].prec_arg] = PA_INT;
+
+      switch (specs[cnt].ndata_args)
+	{
+	case 0:			/* No arguments.  */
+	  break;
+	case 1:			/* One argument; we already have the type.  */
+	  args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type;
+	  break;
+	default:
+	  /* We have more than one argument for this format spec.  We must
+	     call the arginfo function again to determine all the types.  */
+	  (void) (*__printf_arginfo_table[specs[cnt].info.spec])
+	    (&specs[cnt].info,
+	     specs[cnt].ndata_args, &args_type[specs[cnt].data_arg]);
+	  break;
+	}
+    }
+
+  /* Now we know all the types and the order.  Fill in the argument values.  */
+  for (cnt = 0; cnt < nargs; ++cnt)
+    switch (args_type[cnt])
+      {
+#define T(tag, mem, type)						      \
+      case tag:								      \
+	args_value[cnt].mem = va_arg (ap, type);			      \
+	break
+
+	T (PA_CHAR, pa_char, int); /* Promoted.  */
+	T (PA_INT|PA_FLAG_SHORT, pa_short_int, int); /* Promoted.  */
+	T (PA_INT, pa_int, int);
+	T (PA_INT|PA_FLAG_LONG, pa_long_int, long int);
+	T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int);
+	T (PA_FLOAT, pa_float, double);	/* Promoted.  */
+	T (PA_DOUBLE, pa_double, double);
+	T (PA_DOUBLE|PA_FLAG_LONG_DOUBLE, pa_long_double, long double);
+	T (PA_STRING, pa_string, const char *);
+	T (PA_POINTER, pa_pointer, void *);
+#undef T
+      default:
+	if ((args_type[cnt] & PA_FLAG_PTR) != 0)
+	  args_value[cnt].pa_pointer = va_arg (ap, void *);
+	break;
+      }
+
+  /* Write the literal text before the first format.  */
+  outstring (format, lead_str_end - format);
+
+  /* Now walk through all format specifiers and process them.  */
+  for (cnt = 0; cnt < nspecs; ++cnt)
+    {
+      printf_function *function; /* Auxiliary function to do output.  */
+      int is_neg;		/* Decimal integer is negative.  */
+      int base;			/* Base of a number to be written.  */
+      unsigned long long int num; /* Integral number to be written.  */
+      const char *str;		/* String to be written.  */
+      char errorbuf[1024];      /* Buffer sometimes used by %m.  */
+
+      if (specs[cnt].width_arg != -1)
+	{
+	  /* Extract the field width from an argument.  */
+	  specs[cnt].info.width = args_value[specs[cnt].width_arg].pa_int;
+
+	  if (specs[cnt].info.width < 0)
+	    /* If the width value is negative left justification is selected
+	       and the value is taken as being positive.  */
+	    {
+	      specs[cnt].info.width = -specs[cnt].info.width;
+	      specs[cnt].info.left = 1;
+	    }
+	}
+
+      if (specs[cnt].prec_arg != -1)
+	{
+	  /* Extract the precision from an argument.  */
+	  specs[cnt].info.prec = args_value[specs[cnt].prec_arg].pa_int;
+
+	  if (specs[cnt].info.prec < 0)
+	    /* If the precision is negative the precision is omitted.  */
+	    specs[cnt].info.prec = -1;
+	}
+
+      /* Check for a user-defined handler for this spec.  */
+      function = (__printf_function_table == NULL ? NULL :
+                  __printf_function_table[specs[cnt].info.spec]);
+
+      if (function != NULL)
+      use_function:		/* Built-in formats with helpers use this.  */
+	{
+	  int function_done;
+	  unsigned int i;
+	  const void *ptr[specs[cnt].ndata_args];
+
+	  /* Fill in an array of pointers to the argument values.  */
+	  for (i = 0; i < specs[cnt].ndata_args; ++i)
+	    ptr[i] = &args_value[specs[cnt].data_arg + i];
+
+	  /* Call the function.  */
+	  function_done = (*function) (s, &specs[cnt].info, ptr);
+
+	  /* If an error occured don't do any further work.  */
+	  if (function_done < 0)
+	    return -1;
+
+	  done += function_done;
+	}
+      else
+	switch (specs[cnt].info.spec)
+	  {
+	  case '%':
+	    /* Write a literal "%".  */
+	    outchar ('%');
+	    break;
+	  case 'i':
+	  case 'd':
+	    {
+	      long long int signed_num;
+
+	      /* Decimal integer.  */
+	      base = 10;
+	      if (specs[cnt].info.is_longlong)
+		signed_num = args_value[specs[cnt].data_arg].pa_long_long_int;
+	      else if (specs[cnt].info.is_long)
+		signed_num = args_value[specs[cnt].data_arg].pa_long_int;
+	      else if (!specs[cnt].info.is_short)
+		signed_num = args_value[specs[cnt].data_arg].pa_int;
+	      else
+		signed_num = args_value[specs[cnt].data_arg].pa_short_int;
+
+	      is_neg = signed_num < 0;
+	      num = is_neg ? (- signed_num) : signed_num;
+	      goto number;
+	    }
+
+	  case 'u':
+	    /* Decimal unsigned integer.  */
+            base = 10;
+            goto unsigned_number;
+
+	  case 'o':
+            /* Octal unsigned integer.  */
+            base = 8;
+            goto unsigned_number;
+
+          case 'X':
+            /* Hexadecimal unsigned integer.  */
+          case 'x':
+            /* Hex with lower-case digits.  */
+            base = 16;
+
+	  unsigned_number:
+            /* Unsigned number of base BASE.  */
+
+            if (specs[cnt].info.is_longlong)
+	      num = args_value[specs[cnt].data_arg].pa_u_long_long_int;
+            else if (specs[cnt].info.is_long)
+	      num = args_value[specs[cnt].data_arg].pa_u_long_int;
+            else if (!specs[cnt].info.is_short)
+	      num = args_value[specs[cnt].data_arg].pa_u_int;
+            else
+	      num = args_value[specs[cnt].data_arg].pa_u_short_int;
+
+            /* ANSI only specifies the `+' and
+               ` ' flags for signed conversions.  */
+            is_neg = 0;
+	    specs[cnt].info.showsign = 0;
+	    specs[cnt].info.space = 0;
+
+	  number:
+	    /* Number of base BASE.  */
+            {
+              char work[BUFSIZ];
+              char *const workend = &work[sizeof(work) - 1];
+              register char *w;
+
+              /* Supply a default precision if none was given.  */
+              if (specs[cnt].info.prec == -1)
+                specs[cnt].info.prec = 1;
+
+              /* Put the number in WORK.  */
+              w = _itoa (num, workend + 1, base, specs[cnt].info.spec == 'X');
+	      w -= 1;
+              if (specs[cnt].info.group && grouping)
+                w = group_number (w, workend, grouping, thousands_sep);
+              specs[cnt].info.width -= workend - w;
+              specs[cnt].info.prec -= workend - w;
+
+              if (num != 0 && specs[cnt].info.alt && base == 8
+		  && specs[cnt].info.prec <= 0)
+                {
+		  /* Add octal marker.  */
+                  *w-- = '0';
+                  --specs[cnt].info.width;
+                }
+
+              if (specs[cnt].info.prec > 0)
+                {
+		  /* Add zeros to the precision.  */
+                  specs[cnt].info.width -= specs[cnt].info.prec;
+                  while (specs[cnt].info.prec-- > 0)
+                    *w-- = '0';
+                }
+
+              if (num != 0 && specs[cnt].info.alt && base == 16)
+		/* Account for 0X hex marker.  */
+                specs[cnt].info.width -= 2;
+
+              if (is_neg || specs[cnt].info.showsign || specs[cnt].info.space)
+                --specs[cnt].info.width;
+
+              if (!specs[cnt].info.left && specs[cnt].info.pad == ' ')
+                PAD (' ');
+
+              if (is_neg)
+                outchar ('-');
+              else if (specs[cnt].info.showsign)
+                outchar ('+');
+              else if (specs[cnt].info.space)
+                outchar (' ');
+
+              if (num != 0 && specs[cnt].info.alt && base == 16)
+                {
+                  outchar ('0');
+                  outchar (specs[cnt].info.spec);
+                }
+
+              if (!specs[cnt].info.left && specs[cnt].info.pad == '0')
+                PAD ('0');
+
+              /* Write the number.  */
+              while (++w <= workend)
+                outchar (*w);
+
+              if (specs[cnt].info.left)
+                PAD (' ');
+            }
+            break;
+
+          case 'e':
+          case 'E':
+          case 'f':
+          case 'g':
+          case 'G':
+            {
+              /* Floating-point number.  This is handled by printf_fp.c.  */
+              extern printf_function __printf_fp;
+              function = __printf_fp;
+              goto use_function;
+            }
+
+          case 'c':
+            /* Character.  */
+            if (!specs[cnt].info.left)
+              {
+                --specs[cnt].info.width;
+                PAD (' ');
+              }
+            outchar ((unsigned char) args_value[specs[cnt].data_arg].pa_char);
+            if (specs[cnt].info.left)
+              PAD (' ');
+            break;
+
+          case 's':
+            {
+              static const char null[] = "(null)";
+              size_t len;
+
+	      str = args_value[specs[cnt].data_arg].pa_string;
+
+	    string:
+
+              if (str == NULL)
+		{
+		  /* Write "(null)" if there's space.  */
+		  if (specs[cnt].info.prec == -1
+		      || specs[cnt].info.prec >= (int) sizeof (null) - 1)
+		    {
+		      str = null;
+		      len = sizeof (null) - 1;
+		    }
+		  else
+		    {
+		      str = "";
+		      len = 0;
+		    }
+		}
+              else if (specs[cnt].info.prec != -1)
+		{
+		  /* Search for the end of the string, but don't search
+		     past the length specified by the precision.  */
+		  const char *end = memchr (str, '\0', specs[cnt].info.prec);
+		  if (end)
+		    len = end - str;
+		  else
+		    len = specs[cnt].info.prec;
+		}
+	      else
+		len = strlen (str);
+
+              specs[cnt].info.width -= len;
+
+              if (!specs[cnt].info.left)
+                PAD (' ');
+              outstring (str, len);
+              if (specs[cnt].info.left)
+                PAD (' ');
+            }
+            break;
+
+          case 'p':
+            /* Generic pointer.  */
+            {
+              const void *ptr;
+              ptr = args_value[specs[cnt].data_arg].pa_pointer;
+              if (ptr != NULL)
+                {
+                  /* If the pointer is not NULL, write it as a %#x spec.  */
+                  base = 16;
+                  num = (unsigned long long int) (unsigned long int) ptr;
+                  is_neg = 0;
+                  specs[cnt].info.alt = 1;
+		  specs[cnt].info.spec = 'x';
+                  specs[cnt].info.group = 0;
+                  goto number;
+                }
+              else
+                {
+                  /* Write "(nil)" for a nil pointer.  */
+                  str = "(nil)";
+		  /* Make sure the full string "(nil)" is printed.  */
+		  if (specs[cnt].info.prec < 5)
+		    specs[cnt].info.prec = 5;
+                  goto string;
+                }
+            }
+            break;
+
+          case 'n':
+            /* Answer the count of characters written.  */
+            if (specs[cnt].info.is_longlong)
+	      *(long long int *) 
+		args_value[specs[cnt].data_arg].pa_pointer = done;
+            else if (specs[cnt].info.is_long)
+	      *(long int *) 
+		args_value[specs[cnt].data_arg].pa_pointer = done;
+            else if (!specs[cnt].info.is_short)
+	      *(int *) 
+		args_value[specs[cnt].data_arg].pa_pointer = done;
+            else
+	      *(short int *) 
+		args_value[specs[cnt].data_arg].pa_pointer = done;
+            break;
+
+          case 'm':
+            {
+              extern char *_strerror_internal __P ((int, char *buf, size_t));
+              str = _strerror_internal (errno, errorbuf, sizeof errorbuf);
+              goto string;
+            }
+
+          default:
+            /* Unrecognized format specifier.  */
+            function = printf_unknown;
+            goto use_function;
+	  }
+
+      /* Write the following constant string.  */
+      outstring (specs[cnt].end_of_fmt,
+		 specs[cnt].next_fmt - specs[cnt].end_of_fmt);
+    }
+
+  return done;
+}
+
+
+/* Handle an unknown format specifier.  This prints out a canonicalized
+   representation of the format spec itself.  */
+
+static int
+printf_unknown (s, info, args)
+  FILE *s;
+  const struct printf_info *info;
+  const void **const args;
+{
+  int done = 0;
+  char work[BUFSIZ];
+  char *const workend = &work[sizeof(work) - 1];
+  register char *w;
+
+  outchar ('%');
+
+  if (info->alt)
+    outchar ('#');
+  if (info->group)
+    outchar ('\'');
+  if (info->showsign)
+    outchar ('+');
+  else if (info->space)
+    outchar (' ');
+  if (info->left)
+    outchar ('-');
+  if (info->pad == '0')
+    outchar ('0');
+
+  if (info->width != 0)
+    {
+      w = _itoa (info->width, workend + 1, 10, 0);
+      while (++w <= workend)
+	outchar (*w);
+    }
+
+  if (info->prec != -1)
+    {
+      outchar ('.');
+      w = _itoa (info->prec, workend + 1, 10, 0);
+      while (++w <= workend)
+	outchar (*w);
+    }
+
+  if (info->spec != '\0')
+    outchar (info->spec);
+
+  return done;
+}
+
+/* Group the digits according to the grouping rules of the current locale.
+   The interpretation of GROUPING is as in `struct lconv' from <locale.h>.  */
+
+static char *
+group_number (char *w, char *workend, const char *grouping,
+	      wchar_t thousands_sep)
+{
+  int len;
+  char *src, *s;
+
+  /* We treat all negative values like CHAR_MAX.  */
+
+  if (*grouping == CHAR_MAX || *grouping < 0)
+    /* No grouping should be done.  */
+    return w;
+
+  len = *grouping;
+
+  /* Copy existing string so that nothing gets overwritten.  */
+  src = (char *) alloca (workend - w);
+  memcpy (src, w + 1, workend - w);
+  s = &src[workend - w - 1];
+  w = workend;
+
+  /* Process all characters in the string.  */
+  while (s >= src)
+    {
+      *w-- = *s--;
+
+      if (--len == 0 && s >= src)
+	{
+	  /* A new group begins.  */
+	  *w-- = thousands_sep;
+
+	  len = *grouping++;
+	  if (*grouping == '\0')
+	    /* The previous grouping repeats ad infinitum.  */
+	    --grouping;
+	  else if (*grouping == CHAR_MAX || *grouping < 0)
+	    {
+	      /* No further grouping to be done.
+		 Copy the rest of the number.  */
+	      do
+		*w-- = *s--;
+	      while (s >= src);
+	      break;
+	    }
+	}
+    }
+  return w;
+}
+
+#ifdef USE_IN_LIBIO
+/* Helper "class" for `fprintf to unbuffered': creates a temporary buffer.  */
+struct helper_file
+  {
+    struct _IO_FILE_plus _f;
+    _IO_FILE *_put_stream;
+  };
+
+static int
+_IO_helper_overflow (s, c)
+  _IO_FILE *s;
+  int c;
+{
+  _IO_FILE *target = ((struct helper_file*) s)->_put_stream;
+  int used = s->_IO_write_ptr - s->_IO_write_base;
+  if (used)
+    {
+      _IO_size_t written = _IO_sputn (target, s->_IO_write_base, used);
+      s->_IO_write_ptr -= written;
+    }
+  return _IO_putc (c, s);
+}
+
+static const struct _IO_jump_t _IO_helper_jumps =
+  {
+    _IO_helper_overflow,
+    _IO_default_underflow,
+    _IO_default_xsputn,
+    _IO_default_xsgetn,
+    _IO_default_read,
+    _IO_default_write,
+    _IO_default_doallocate,
+    _IO_default_pbackfail,
+    _IO_default_setbuf,
+    _IO_default_sync,
+    _IO_default_finish,
+    _IO_default_close,
+    _IO_default_stat,
+    _IO_default_seek,
+    _IO_default_seekoff,
+    _IO_default_seekpos,
+    _IO_default_uflow
+  };
+
+static int
+buffered_vfprintf (s, format, args)
+  register _IO_FILE *s;
+  char const *format;
+  _IO_va_list args;
+{
+  char buf[_IO_BUFSIZ];
+  struct helper_file helper;
+  register _IO_FILE *hp = (_IO_FILE *) &helper;
+  int result, to_flush;
+
+  /* Initialize helper.  */
+  helper._put_stream = s;
+  hp->_IO_write_base = buf;
+  hp->_IO_write_ptr = buf;
+  hp->_IO_write_end = buf + sizeof buf;
+  hp->_IO_file_flags = _IO_MAGIC|_IO_NO_READS;
+  hp->_jumps = (struct _IO_jump_t *) &_IO_helper_jumps;
+  
+  /* Now print to helper instead.  */
+  result = _IO_vfprintf (hp, format, args);
+
+  /* Now flush anything from the helper to the S. */
+  if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
+    {
+      if (_IO_sputn (s, hp->_IO_write_base, to_flush) != to_flush)
+	return -1;
+    }
+
+  return result;
+}
+
+#else /* !USE_IN_LIBIO */
+
+static int
+buffered_vfprintf (s, format, args)
+  register FILE *s;
+  char const *format;
+  va_list args;
+{
+  char buf[BUFSIZ];
+  int result;
+
+  s->__bufp = s->__buffer = buf;
+  s->__bufsize = sizeof buf;
+  s->__put_limit = s->__buffer + s->__bufsize;
+  s->__get_limit = s->__buffer;
+
+  /* Now use buffer to print.  */
+  result = vfprintf (s, format, args);
+
+  if (fflush (s) == EOF)
+    result = -1;
+  s->__buffer = s->__bufp = s->__get_limit = s->__put_limit = NULL;
+  s->__bufsize = 0;
+
+  return result;
+}
+
+
+/* Pads string with given number of a specified character.
+   This code is taken from iopadn.c of the GNU I/O library.  */
+#define PADSIZE 16
+static const char blanks[PADSIZE] =
+{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
+static const char zeroes[PADSIZE] =
+{'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
+
+ssize_t
+__printf_pad (s, pad, count)
+     FILE *s;
+     char pad;
+     size_t count;
+{
+  const char *padptr;
+  register size_t i;
+
+  padptr = pad == ' ' ? blanks : zeroes;
+
+  for (i = count; i >= PADSIZE; i -= PADSIZE)
+    if (PUT (s, padptr, PADSIZE) != PADSIZE)
+      return -1;
+  if (i > 0)
+    if (PUT (s, padptr, i) != i)
+      return -1;
+
+  return count;
+}
+#undef PADSIZE
+#endif /* USE_IN_LIBIO */
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c
new file mode 100644
index 0000000000..a778346287
--- /dev/null
+++ b/stdio-common/vfscanf.c
@@ -0,0 +1,624 @@
+/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include "../locale/localeinfo.h"
+#include <errno.h>
+#include <limits.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#ifdef	__GNUC__
+#define	HAVE_LONGLONG
+#define	LONGLONG	long long
+#else
+#define	LONGLONG	long
+#endif
+
+
+#define	inchar()	((c = getc(s)) == EOF ? EOF : (++read_in, c))
+#define	conv_error()	return (ungetc(c, s), done)
+#define input_error()	return (done == 0 ? EOF : done)
+#define	memory_error()	return ((errno = ENOMEM), EOF)
+
+
+/* Read formatted input from S according to the format string
+   FORMAT, using the argument list in ARG.
+   Return the number of assignments made, or -1 for an input error.  */
+int
+DEFUN(__vfscanf, (s, format, arg),
+      FILE *s AND CONST char *format AND va_list argptr)
+{
+  va_list arg = (va_list) argptr;
+
+  register CONST char *f = format;
+  register char fc;		/* Current character of the format.  */
+  register size_t done = 0;	/* Assignments done.  */
+  register size_t read_in = 0;	/* Chars read in.  */
+  register int c;		/* Last char read.  */
+  register int do_assign;	/* Whether to do an assignment.  */
+  register int width;		/* Maximum field width.  */
+  int group_flag;		/* %' modifier flag.  */
+
+  /* Type modifiers.  */
+  int is_short, is_long, is_long_double;
+#ifdef	HAVE_LONGLONG
+  /* We use the `L' modifier for `long long int'.  */
+#define	is_longlong	is_long_double
+#else
+#define	is_longlong	0
+#endif
+  int malloc_string;		/* Args are char ** to be filled in.  */
+  /* Status for reading F-P nums.  */
+  char got_dot, got_e;
+  /* If a [...] is a [^...].  */
+  char not_in;
+  /* Base for integral numbers.  */
+  int base;
+  /* Signedness for integral numbers.  */
+  int number_signed;
+  /* Integral holding variables.  */
+  union
+    {
+      long long int q;
+      unsigned long long int uq;
+      long int l;
+      unsigned long int ul;
+    } num;
+  /* Character-buffer pointer.  */
+  register char *str, **strptr;
+  size_t strsize;
+  /* Workspace.  */
+  char work[200];
+  char *w;			/* Pointer into WORK.  */
+  wchar_t decimal;		/* Decimal point character.  */
+
+  if (!__validfp(s) || !s->__mode.__read || format == NULL)
+    {
+      errno = EINVAL;
+      return EOF;
+    }
+
+  /* Figure out the decimal point character.  */
+  if (mbtowc (&decimal, _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT),
+	      strlen (_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT))) <= 0)
+    decimal = (wchar_t) *_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
+
+  c = inchar();
+
+  /* Run through the format string.  */
+  while (*f != '\0')
+    {
+      unsigned int argpos;
+      /* Extract the next argument, which is of type TYPE.
+	 For a %N$... spec, this is the Nth argument from the beginning;
+	 otherwise it is the next argument after the state now in ARG.  */
+#define ARG(type)	(argpos == 0 ? va_arg (arg, type) :		      \
+			 ({ unsigned int pos = argpos;			      \
+			    va_list arg = (va_list) argptr;		      \
+			    while (--pos > 0)				      \
+			      (void) va_arg (arg, void *);		      \
+			    va_arg (arg, type);				      \
+			  }))
+
+      if (!isascii (*f))
+	{
+	  /* Non-ASCII, may be a multibyte.  */
+	  int len = mblen (f, strlen(f));
+	  if (len > 0)
+	    {
+	      while (len-- > 0)
+		if (c == EOF)
+		  input_error();
+		else if (c == *f++)
+		  (void) inchar();
+		else
+		  conv_error();
+	      continue;
+	    }
+	}
+
+      fc = *f++;
+      if (fc != '%')
+	{
+	  /* Characters other than format specs must just match.  */
+	  if (c == EOF)
+	    input_error();
+	  if (isspace(fc))
+	    {
+	      /* Whitespace characters match any amount of whitespace.  */
+	      while (isspace (c))
+		inchar ();
+	      continue;
+	    }
+	  else if (c == fc)
+	    (void) inchar();
+	  else
+	    conv_error();
+	  continue;
+	}
+
+      /* Initialize state of modifiers.  */
+      argpos = 0;
+      do_assign = 1;
+      group_flag = 0;
+      is_short = is_long = is_long_double = malloc_string = 0;
+
+      /* Check for a positional parameter specification.  */
+      if (isdigit (*f))
+	{
+	  argpos = *f++ - '0';
+	  while (isdigit (*f))
+	    argpos = argpos * 10 + (*f++ - '0');
+	  if (*f == '$')
+	    ++f;
+	  else
+	    {
+	      /* Oops; that was actually the field width.  */
+	      width = argpos;
+	      argpos = 0;
+	      goto got_width;
+	    }
+	}
+
+      /* Check for the assignment-suppressant and the number grouping flag.  */
+      while (*f == '*' || *f == '\'')
+	switch (*f++)
+	  {
+	  case '*':
+	    do_assign = 0;
+	    break;
+	  case '\'':
+	    group_flag = 1;
+	    break;
+	  }
+
+      /* Find the maximum field width.  */
+      width = 0;
+      while (isdigit(*f))
+	{
+	  width *= 10;
+	  width += *f++ - '0';
+	}
+    got_width:
+      if (width == 0)
+	width = -1;
+
+      /* Check for type modifiers.  */
+      while (*f == 'h' || *f == 'l' || *f == 'L' || *f == 'a' || *f == 'q')
+	switch (*f++)
+	  {
+	  case 'h':
+	    /* int's are short int's.  */
+	    is_short = 1;
+	    break;
+	  case 'l':
+	    if (is_long)
+	      /* A double `l' is equivalent to an `L'.  */
+	      is_longlong = 1;
+	    else
+	      /* int's are long int's.  */
+	      is_long = 1;
+	    break;
+	  case 'q':
+	  case 'L':
+	    /* double's are long double's, and int's are long long int's.  */
+	    is_long_double = 1;
+	    break;
+	  case 'a':
+	    /* String conversions (%s, %[) take a `char **'
+	       arg and fill it in with a malloc'd pointer.  */
+	    malloc_string = 1;
+	    break;
+	  }
+
+      /* End of the format string?  */
+      if (*f == '\0')
+	conv_error();
+
+      /* Find the conversion specifier.  */
+      w = work;
+      fc = *f++;
+      if (fc != '[' && fc != 'c' && fc != 'n')
+	/* Eat whitespace.  */
+	while (isspace(c))
+	  (void) inchar();
+      switch (fc)
+	{
+	case '%':	/* Must match a literal '%'.  */
+	  if (c != fc)
+	    conv_error();
+	  break;
+
+	case 'n':	/* Answer number of assignments done.  */
+	  if (do_assign)
+	    *ARG (int *) = read_in - 1;	/* Don't count the read-ahead.  */
+	  break;
+
+	case 'c':	/* Match characters.  */
+	  if (do_assign)
+	    {
+	      str = ARG (char *);
+	      if (str == NULL)
+		conv_error ();
+	    }
+
+	  if (c == EOF)
+	    input_error();
+
+	  if (width == -1)
+	    width = 1;
+
+	  if (do_assign)
+	    {
+	      do
+		*str++ = c;
+	      while (inchar() != EOF && --width > 0);
+	    }
+	  else
+	    while (inchar() != EOF && --width > 0);
+
+	  if (do_assign)
+	    ++done;
+
+	  break;
+
+	case 's':		/* Read a string.  */
+#define STRING_ARG							      \
+	  if (do_assign)						      \
+	    {								      \
+	      if (malloc_string)					      \
+		{							      \
+		  /* The string is to be stored in a malloc'd buffer.  */     \
+		  strptr = ARG (char **);			      \
+		  if (strptr == NULL)					      \
+		    conv_error ();					      \
+		  /* Allocate an initial buffer.  */			      \
+		  strsize = 100;					      \
+		  *strptr = str = malloc (strsize);			      \
+		}							      \
+	      else							      \
+		str = ARG (char *);				      \
+	      if (str == NULL)						      \
+		conv_error ();						      \
+	    }
+	  STRING_ARG;
+
+	  if (c == EOF)
+	    input_error ();
+
+	  do
+	    {
+	      if (isspace (c))
+		break;
+#define	STRING_ADD_CHAR(c)						      \
+	      if (do_assign)						      \
+		{							      \
+		  *str++ = c;						      \
+		  if (malloc_string && str == *strptr + strsize)	      \
+		    {							      \
+		      /* Enlarge the buffer.  */			      \
+		      str = realloc (*strptr, strsize * 2);		      \
+		      if (str == NULL)					      \
+			{						      \
+			  /* Can't allocate that much.  Last-ditch effort.  */\
+			  str = realloc (*strptr, strsize + 1);		      \
+			  if (str == NULL)				      \
+			    {						      \
+			      /* We lose.  Oh well.			      \
+				 Terminate the string and stop converting,    \
+				 so at least we don't swallow any input.  */  \
+			      (*strptr)[strsize] = '\0';		      \
+			      ++done;					      \
+			      conv_error ();				      \
+			    }						      \
+			  else						      \
+			    {						      \
+			      *strptr = str;				      \
+			      str += strsize;				      \
+			      ++strsize;				      \
+			    }						      \
+			}						      \
+		      else						      \
+			{						      \
+			  *strptr = str;				      \
+			  str += strsize;				      \
+			  strsize *= 2;					      \
+			}						      \
+		    }							      \
+		}
+	      STRING_ADD_CHAR (c);
+	    } while (inchar () != EOF && (width <= 0 || --width > 0));
+
+	  if (do_assign)
+	    {
+	      *str = '\0';
+	      ++done;
+	    }
+	  break;
+
+	case 'x':	/* Hexadecimal integer.  */
+	case 'X':	/* Ditto.  */ 
+	  base = 16;
+	  number_signed = 0;
+	  goto number;
+
+	case 'o':	/* Octal integer.  */
+	  base = 8;
+	  number_signed = 0;
+	  goto number;
+
+	case 'u':	/* Unsigned decimal integer.  */
+	  base = 10;
+	  number_signed = 0;
+	  goto number;
+
+	case 'd':	/* Signed decimal integer.  */
+	  base = 10;
+	  number_signed = 1;
+	  goto number;
+
+	case 'i':	/* Generic number.  */
+	  base = 0;
+	  number_signed = 1;
+
+	number:
+	  if (c == EOF)
+	    input_error();
+
+	  /* Check for a sign.  */
+	  if (c == '-' || c == '+')
+	    {
+	      *w++ = c;
+	      if (width > 0)
+		--width;
+	      (void) inchar();
+	    }
+
+	  /* Look for a leading indication of base.  */
+	  if (c == '0')
+	    {
+	      if (width > 0)
+		--width;
+	      *w++ = '0';
+
+	      (void) inchar();
+
+	      if (tolower(c) == 'x')
+		{
+		  if (base == 0)
+		    base = 16;
+		  if (base == 16)
+		    {
+		      if (width > 0)
+			--width;
+		      (void) inchar();
+		    }
+		}
+	      else if (base == 0)
+		base = 8;
+	    }
+
+	  if (base == 0)
+	    base = 10;
+
+	  /* Read the number into WORK.  */
+	  while (width != 0 && c != EOF)
+	    {
+	      if (base == 16 ? !isxdigit(c) :
+		  (!isdigit(c) || c - '0' >= base))
+		break;
+	      *w++ = c;
+	      if (width > 0)
+		--width;
+	      (void) inchar ();
+	    }
+
+	  if (w == work ||
+	      (w - work == 1 && (work[0] == '+' || work[0] == '-')))
+	    /* There was no number.  */
+	    conv_error();
+
+	  /* Convert the number.  */
+	  *w = '\0';
+	  if (is_longlong)
+	    {
+	      if (number_signed)
+		num.q = __strtoq_internal (work, &w, base, group_flag);
+	      else
+		num.uq = __strtouq_internal (work, &w, base, group_flag);
+	    }
+	  else
+	    {
+	      if (number_signed)
+		num.l = __strtol_internal (work, &w, base, group_flag);
+	      else
+		num.ul = __strtoul_internal (work, &w, base, group_flag);
+	    }
+	  if (w == work)
+	    conv_error ();
+
+	  if (do_assign)
+	    {
+	      if (! number_signed)
+		{
+		  if (is_longlong)
+		    *ARG (unsigned LONGLONG int *) = num.uq;
+		  else if (is_long)
+		    *ARG (unsigned long int *) = num.ul;
+		  else if (is_short)
+		    *ARG (unsigned short int *)
+		      = (unsigned short int) num.ul;
+		  else
+		    *ARG (unsigned int *) = (unsigned int) num.ul;
+		}
+	      else
+		{
+		  if (is_longlong)
+		    *ARG (LONGLONG int *) = num.q;
+		  else if (is_long)
+		    *ARG (long int *) = num.l;
+		  else if (is_short)
+		    *ARG (short int *) = (short int) num.l;
+		  else
+		    *ARG (int *) = (int) num.l;
+		}
+	      ++done;
+	    }
+	  break;
+
+	case 'e':	/* Floating-point numbers.  */
+	case 'E':
+	case 'f':
+	case 'g':
+	case 'G':
+	  if (c == EOF)
+	    input_error();
+
+	  /* Check for a sign.  */
+	  if (c == '-' || c == '+')
+	    {
+	      *w++ = c;
+	      if (inchar() == EOF)
+		/* EOF is only an input error before we read any chars.  */
+		conv_error();
+	      if (width > 0)
+		--width;
+	    }
+
+	  got_dot = got_e = 0;
+	  do
+	    {
+	      if (isdigit(c))
+		*w++ = c;
+	      else if (got_e && w[-1] == 'e' && (c == '-' || c == '+'))
+		*w++ = c;
+	      else if (!got_e && tolower(c) == 'e')
+		{
+		  *w++ = 'e';
+		  got_e = got_dot = 1;
+		}
+	      else if (c == decimal && !got_dot)
+		{
+		  *w++ = c;
+		  got_dot = 1;
+		}
+	      else
+		break;
+	      if (width > 0)
+		--width;
+	    } while (inchar() != EOF && width != 0);
+
+	  if (w == work)
+	    conv_error();
+	  if (w[-1] == '-' || w[-1] == '+' || w[-1] == 'e')
+	    conv_error();
+
+	  /* Convert the number.  */
+	  *w = '\0';
+	  if (is_long_double)
+	    {
+	      long double d = __strtold_internal (work, &w, group_flag);
+	      if (do_assign && w != work)
+		*ARG (long double *) = d;
+	    }
+	  else if (is_long)
+	    {
+	      double d = __strtod_internal (work, &w, group_flag);
+	      if (do_assign && w != work)
+		*ARG (double *) = d;
+	    }
+	  else
+	    {
+	      float d = __strtof_internal (work, &w, group_flag);
+	      if (do_assign && w != work)
+		*ARG (float *) = d;
+	    }
+
+	  if (w == work)
+	    conv_error ();
+
+	  if (do_assign)
+	    ++done;
+	  break;
+
+	case '[':	/* Character class.  */
+	  STRING_ARG;
+
+	  if (c == EOF)
+	    input_error();
+
+	  if (*f == '^')
+	    {
+	      ++f;
+	      not_in = 1;
+	    }
+	  else
+	    not_in = 0;
+
+	  while ((fc = *f++) != '\0' && fc != ']')
+	    {
+	      if (fc == '-' && *f != '\0' && *f != ']' &&
+		  w > work && w[-1] <= *f)
+		/* Add all characters from the one before the '-'
+		   up to (but not including) the next format char.  */
+		for (fc = w[-1] + 1; fc < *f; ++fc)
+		  *w++ = fc;
+	      else
+		/* Add the character to the list.  */
+		*w++ = fc;
+	    }
+	  if (fc == '\0')
+	    conv_error();
+
+	  *w = '\0';
+	  num.ul = read_in;
+	  do
+	    {
+	      if ((strchr (work, c) == NULL) != not_in)
+		break;
+	      STRING_ADD_CHAR (c);
+	      if (width > 0)
+		--width;
+	    } while (inchar () != EOF && width != 0);
+	  if (read_in == num.ul)
+	    conv_error ();
+
+	  if (do_assign)
+	    {
+	      *str = '\0';
+	      ++done;
+	    }
+	  break;
+
+	case 'p':	/* Generic pointer.  */
+	  base = 16;
+	  /* A PTR must be the same size as a `long int'.  */
+	  is_long = 1;
+	  goto number;
+	}
+    }
+
+  conv_error();
+}
+
+weak_alias (__vfscanf, vfscanf)
diff --git a/stdio-common/vprintf.c b/stdio-common/vprintf.c
new file mode 100644
index 0000000000..77f1da47e2
--- /dev/null
+++ b/stdio-common/vprintf.c
@@ -0,0 +1,37 @@
+/* Copyright (C) 1991, 1993, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <stdarg.h>
+#undef	__OPTIMIZE__	/* Avoid inline `vprintf' function.  */
+#include <stdio.h>
+
+#undef	vprintf
+
+#ifdef USE_IN_LIBIO
+# define vfprintf _IO_vfprintf
+#endif
+
+/* Write formatted output to stdout according to the
+   format string FORMAT, using the argument list in ARG.  */
+int
+vprintf (format, arg)
+     const char *format;
+     __gnuc_va_list arg;
+{
+  return vfprintf (stdout, format, arg);
+}
diff --git a/stdio-common/vscanf.c b/stdio-common/vscanf.c
new file mode 100644
index 0000000000..0d829440e9
--- /dev/null
+++ b/stdio-common/vscanf.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#undef	vscanf
+
+
+/* Read formatted input from stdin according to the format
+   string in FORMAT, using the argument list in ARG.  */
+int
+DEFUN(vscanf, (format, arg), CONST char *format AND va_list arg)
+{
+  return vfscanf (stdin, format, arg);
+}
diff --git a/stdio-common/vsnprintf.c b/stdio-common/vsnprintf.c
new file mode 100644
index 0000000000..a02c259131
--- /dev/null
+++ b/stdio-common/vsnprintf.c
@@ -0,0 +1,56 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+
+/*
+ * Write formatted output to S according to the format string
+ * FORMAT, using the argument list in ARG, writing no more
+ * than MAXLEN characters.
+ */
+int
+DEFUN(vsnprintf, (s, maxlen, format, arg),
+	char *s AND size_t maxlen AND CONST char *format AND va_list arg)
+{
+  int done;
+  FILE f;
+
+  memset((PTR) &f, 0, sizeof(f));
+  f.__magic = _IOMAGIC;
+  f.__mode.__write = 1;
+  /* The buffer size is one less than MAXLEN
+     so we have space for the null terminator.  */
+  f.__bufp = f.__buffer = (char *) s;
+  f.__bufsize = maxlen - 1;
+  f.__put_limit = f.__buffer + f.__bufsize;
+  f.__get_limit = f.__buffer;
+  /* After the buffer is full (MAXLEN characters have been written),
+     any more characters written will go to the bit bucket.  */
+  f.__room_funcs = __default_room_functions;
+  f.__io_funcs.__write = NULL;
+  f.__seen = 1;
+
+  done = vfprintf(&f, format, arg);
+  *f.__bufp = '\0';
+
+  return done;
+}
diff --git a/stdio-common/vsprintf.c b/stdio-common/vsprintf.c
new file mode 100644
index 0000000000..82be90f1fa
--- /dev/null
+++ b/stdio-common/vsprintf.c
@@ -0,0 +1,50 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+
+/* Write formatted output to S according to the format string
+   FORMAT, using the argument list in ARG.  */
+int
+DEFUN(vsprintf, (s, format, arg),
+      char *s AND CONST char *format AND va_list arg)
+{
+  int done;
+  FILE f;
+
+  memset((PTR) &f, 0, sizeof(f));
+  f.__magic = _IOMAGIC;
+  f.__mode.__write = 1;
+  f.__bufp = f.__buffer = (char *) s;
+  f.__put_limit = (char *) ULONG_MAX;
+  f.__bufsize = (size_t) (f.__put_limit - f.__bufp);
+  f.__get_limit = f.__buffer;
+  f.__room_funcs.__output = NULL;
+  f.__seen = 1;
+
+  done = vfprintf(&f, format, arg);
+  *f.__bufp = '\0';
+
+  return done;
+}
diff --git a/stdio-common/vsscanf.c b/stdio-common/vsscanf.c
new file mode 100644
index 0000000000..6f027d5065
--- /dev/null
+++ b/stdio-common/vsscanf.c
@@ -0,0 +1,58 @@
+/* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+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., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#undef	vsscanf
+
+
+/* Read formatted input from S according to the format
+   string FORMAT, using the argument list in ARG.  */
+int
+DEFUN(__vsscanf, (s, format, arg),
+      CONST char *s AND CONST char *format AND va_list arg)
+{
+  FILE f;
+
+  if (s == NULL)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  memset((PTR) &f, 0, sizeof(f));
+  f.__magic = _IOMAGIC;
+  f.__mode.__read = 1;
+  f.__bufp = f.__buffer = (char *) s;
+  f.__bufsize = strlen(s);
+  f.__get_limit = f.__buffer + f.__bufsize;
+  f.__put_limit = f.__buffer;
+  /* After the buffer is empty (strlen(S) characters have been read),
+     any more read attempts will get EOF.  */
+  f.__room_funcs.__input = NULL;
+  f.__seen = 1;
+
+  return __vfscanf(&f, format, arg);
+}
+
+
+weak_alias (__vsscanf, vsscanf)
diff --git a/stdio-common/xbug.c b/stdio-common/xbug.c
new file mode 100644
index 0000000000..ec648f5566
--- /dev/null
+++ b/stdio-common/xbug.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+
+typedef struct _Buffer {
+  char *buff;
+  int  room, used;
+} Buffer;
+
+#define INIT_BUFFER_SIZE 10000
+
+void InitBuffer(b)
+     Buffer *b;
+{
+  b->room = INIT_BUFFER_SIZE;
+  b->used = 0;
+  b->buff = (char *)malloc(INIT_BUFFER_SIZE*sizeof(char));
+}
+
+void AppendToBuffer(b, str, len)
+     register Buffer *b;
+     char *str;
+     register int len;
+{
+  while (b->used + len > b->room) {
+    b->buff = (char *)realloc(b->buff, 2*b->room*(sizeof(char)));
+    b->room *= 2;
+  }
+  strncpy(b->buff + b->used, str, len);
+  b->used += len;
+}
+
+void ReadFile(buffer, input)
+     register Buffer *buffer;
+     FILE *input;
+{
+  char       buf[BUFSIZ + 1];
+  register int        bytes;
+
+  buffer->used = 0;
+  while (!feof(input) && (bytes = fread(buf, 1, BUFSIZ, input)) > 0) {
+    AppendToBuffer(buffer, buf, bytes);
+  }
+  AppendToBuffer(buffer, "", 1);
+}
+
+main() 
+{
+  char * filename = "xbug.c";
+  FILE *input;
+  Buffer buffer;
+  
+  InitBuffer(&buffer);
+    
+  if (!freopen (filename, "r", stdin))
+    fprintf(stderr, "cannot open file\n");
+  
+  if (!(input = popen("/bin/cat", "r")))
+    fprintf(stderr, "cannot run \n");
+  
+  ReadFile(&buffer, input);
+  pclose(input);
+
+  return 0;
+}