summaryrefslogtreecommitdiff
path: root/stdio-common
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1995-10-17 00:41:39 +0000
committerRoland McGrath <roland@gnu.org>1995-10-17 00:41:39 +0000
commitdeab9deadc372fe1a367aef2e78c0d8f2885bf23 (patch)
tree367eaf76a86934f3883f950da5719ca581185ca5 /stdio-common
parent10fd03c6014206b3775be893727f282c4c709ebf (diff)
* Makefile (subdirs): Replace stdio with stdio-common and $(stdio).
* configure.in: Grok arg --enable-libio. ($stdio = libio): Define USE_IN_LIBIO. * config.h.in (USE_IN_LIBIO): Add #undef. * config.make.in (stdio): New variable, set by configure. * Makeconfig (stdio): New variable. * stdio.h [USE_IN_LIBIO]: Include libio/stdio.h instead of stdio/stdio.h. * stdio-common/Makefile: New file. * stdio/Makefile: Half the contents moved to stdio-common/Makefile. * stdio/_itoa.c: Moved to stdio-common. * stdio/_itoa.h: Moved to stdio-common. * stdio/asprintf.c: Moved to stdio-common. * stdio/bug1.c: Moved to stdio-common. * stdio/bug1.input: Moved to stdio-common. * stdio/bug2.c: Moved to stdio-common. * stdio/bug3.c: Moved to stdio-common. * stdio/bug4.c: Moved to stdio-common. * stdio/bug5.c: Moved to stdio-common. * stdio/bug6.c: Moved to stdio-common. * stdio/bug6.input: Moved to stdio-common. * stdio/bug7.c: Moved to stdio-common. * stdio/dprintf.c: Moved to stdio-common. * stdio/errnobug.c: Moved to stdio-common. * stdio/getline.c: Moved to stdio-common. * stdio/getw.c: Moved to stdio-common. * stdio/perror.c: Moved to stdio-common. * stdio/printf-parse.h: Moved to stdio-common. * stdio/printf-prs.c: Moved to stdio-common. * stdio/printf.c: Moved to stdio-common. * stdio/printf.h: Moved to stdio-common. * stdio/printf_fp.c: Moved to stdio-common. * stdio/psignal.c: Moved to stdio-common. * stdio/putw.c: Moved to stdio-common. * stdio/reg-printf.c: Moved to stdio-common. * stdio/scanf.c: Moved to stdio-common. * stdio/snprintf.c: Moved to stdio-common. * stdio/sprintf.c: Moved to stdio-common. * stdio/sscanf.c: Moved to stdio-common. * stdio/tempnam.c: Moved to stdio-common. * stdio/temptest.c: Moved to stdio-common. * stdio/test-fseek.c: Moved to stdio-common. * stdio/test-fwrite.c: Moved to stdio-common. * stdio/test-popen.c: Moved to stdio-common. * stdio/test_rdwr.c: Moved to stdio-common. * stdio/tmpfile.c: Moved to stdio-common. * stdio/tmpnam.c: Moved to stdio-common. * stdio/tst-fileno.c: Moved to stdio-common. * stdio/tst-printf.c: Moved to stdio-common. * stdio/tstgetln.c: Moved to stdio-common. * stdio/tstgetln.input: Moved to stdio-common. * stdio/tstscanf.c: Moved to stdio-common. * stdio/tstscanf.input: Moved to stdio-common. * stdio/vfprintf.c: Moved to stdio-common. * stdio/vfscanf.c: Moved to stdio-common. * stdio/vprintf.c: Moved to stdio-common. * stdio/xbug.c: Moved to stdio-common. * sysdeps/generic/Makefile (siglist.c rules): Do this in subdir stdio-common instead of stdio. * sysdeps/unix/Makefile (errlist.c rules): Likewise. * stdio-common/asprintf.c [USE_IN_LIBIO]: Call libio primitive function. * stdio-common/dprintf.c: Likewise. * stdio-common/printf.c: Likewise. * stdio-common/scanf.c: Likewise. * stdio-common/snprintf.c: Likewise. * stdio-common/sprintf.c: Likewise. * stdio-common/sscanf.c: Likewise. * stdio-common/vprintf.c: Likewise. * Makerules: Include $(+depfiles) directly instead of generating depend-$(subdir). (depend-$(subdir)): Target removed. (common-clean): Don't remove depend-$(subdir).
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;
+}