OSDN Git Service

2002-04-19 Jeff Johnston <jjohnstn@redhat.com>
authorjjohnstn <jjohnstn>
Fri, 19 Apr 2002 19:16:02 +0000 (19:16 +0000)
committerjjohnstn <jjohnstn>
Fri, 19 Apr 2002 19:16:02 +0000 (19:16 +0000)
        *  configure.host: Add support for powerpc-eabialtivec*.
        *  libc/include/malloc.h: Add include of <machine/malloc.h>.
        *  libc/include/stdlib.h: Add include of <machine/stdlib.h>.
        *  libc/include/machine/malloc.h: New file.
        *  libc/include/machine/stdlib.h: Ditto.
        *  libc/include/machine/setjmp.h: Add support for powerpc altivec.
        *  libc/machine/powerpc/Makefile.am: Add conditional objects and
        sources based on configuration.
        *  libc/machine/powerpc/Makefile.in: Regenerated.
        *  libc/machine/powerpc/configure: Ditto.
        *  libc/machine/powerpc/configure.in: Add check for
        powerpc-eabialtivec* in which case add in additional source files.
        *  libc/machine/powerpc/setjmp.S: Add altivec support.
        *  libc/machine/powerpc/vec_calloc.c: New file.
        *  libc/machine/powerpc/vec_free.c: Ditto.
        *  libc/machine/powerpc/vec_malloc.c: Ditto.
        *  libc/machine/powerpc/vec_mallocr.c: Ditto.
        *  libc/machine/powerpc/vec_realloc.c: Ditto.
        *  libc/machine/powerpc/machine/malloc.h: Ditto.
        *  libc/machine/powerpc/machine/stdlib.h: Ditto.
        *  libc/machine/powerpc/vfprintf.c: New file that is vfprintf.c
        with added altivec format specifiers.
        *  libc/machine/powerpc/vfscanf.c: New file that is vfscanf.c with
        added altivec format specifiers.

21 files changed:
newlib/ChangeLog
newlib/configure.host
newlib/libc/include/machine/malloc.h [new file with mode: 0644]
newlib/libc/include/machine/setjmp.h
newlib/libc/include/machine/stdlib.h [new file with mode: 0644]
newlib/libc/include/malloc.h
newlib/libc/include/stdlib.h
newlib/libc/machine/powerpc/Makefile.am
newlib/libc/machine/powerpc/Makefile.in
newlib/libc/machine/powerpc/configure
newlib/libc/machine/powerpc/configure.in
newlib/libc/machine/powerpc/machine/malloc.h [new file with mode: 0644]
newlib/libc/machine/powerpc/machine/stdlib.h [new file with mode: 0644]
newlib/libc/machine/powerpc/setjmp.S
newlib/libc/machine/powerpc/vec_calloc.c [new file with mode: 0644]
newlib/libc/machine/powerpc/vec_free.c [new file with mode: 0644]
newlib/libc/machine/powerpc/vec_malloc.c [new file with mode: 0644]
newlib/libc/machine/powerpc/vec_mallocr.c [new file with mode: 0644]
newlib/libc/machine/powerpc/vec_realloc.c [new file with mode: 0644]
newlib/libc/machine/powerpc/vfprintf.c [new file with mode: 0644]
newlib/libc/machine/powerpc/vfscanf.c [new file with mode: 0644]

index a0e370b..45a3ec0 100644 (file)
@@ -1,3 +1,30 @@
+2002-04-19  Jeff Johnston  <jjohnstn@redhat.com>
+
+       *  configure.host: Add support for powerpc-eabialtivec*.
+       *  libc/include/malloc.h: Add include of <machine/malloc.h>.
+       *  libc/include/stdlib.h: Add include of <machine/stdlib.h>.
+       *  libc/include/machine/malloc.h: New file.
+       *  libc/include/machine/stdlib.h: Ditto.
+       *  libc/include/machine/setjmp.h: Add support for powerpc altivec.
+       *  libc/machine/powerpc/Makefile.am: Add conditional objects and
+       sources based on configuration.
+       *  libc/machine/powerpc/Makefile.in: Regenerated.
+       *  libc/machine/powerpc/configure: Ditto.
+       *  libc/machine/powerpc/configure.in: Add check for
+       powerpc-eabialtivec* in which case add in additional source files.
+       *  libc/machine/powerpc/setjmp.S: Add altivec support.
+       *  libc/machine/powerpc/vec_calloc.c: New file.
+       *  libc/machine/powerpc/vec_free.c: Ditto.
+       *  libc/machine/powerpc/vec_malloc.c: Ditto.
+       *  libc/machine/powerpc/vec_mallocr.c: Ditto.
+       *  libc/machine/powerpc/vec_realloc.c: Ditto.
+       *  libc/machine/powerpc/machine/malloc.h: Ditto.
+       *  libc/machine/powerpc/machine/stdlib.h: Ditto.
+       *  libc/machine/powerpc/vfprintf.c: New file that is vfprintf.c
+       with added altivec format specifiers.
+       *  libc/machine/powerpc/vfscanf.c: New file that is vfscanf.c with
+       added altivec format specifiers.
+
 2002-04-19     Joel Sherrill <joel@OARcorp.com>
 
        * libs/sys/rtems/crt0.c: Satisfy gcc's references to libc functions
index 264632e..aaab9c4 100644 (file)
@@ -477,6 +477,9 @@ case "${host}" in
   mn10?00-*-*)
        syscall_dir=syscalls
        ;;
+  powerpc*-*-eabialtivec*)
+       newlib_cflags="${newlib_cflags} -DMISSING_SYSCALL_NAMES -DWANT_PRINTF_LONG_LONG"
+       ;;
   powerpc*-*-eabi* | \
   powerpc*-*-elf* | \
   powerpc*-*-linux* | \
diff --git a/newlib/libc/include/machine/malloc.h b/newlib/libc/include/machine/malloc.h
new file mode 100644 (file)
index 0000000..fdada9e
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef        _MACHMALLOC_H_
+#define        _MACHMALLOC_H_
+
+/* place holder so platforms may add malloc.h extensions */
+
+#endif /* _MACHMALLOC_H_ */
+
+
index c7f1463..e4c788b 100644 (file)
@@ -106,7 +106,11 @@ typedef int jmp_buf[_JBLEN];
 #endif
 
 #ifdef __PPC__
+#ifdef __ALTIVEC__
+#define _JBLEN 64
+#else
 #define _JBLEN 32
+#endif
 #define _JBTYPE double
 #endif
 
diff --git a/newlib/libc/include/machine/stdlib.h b/newlib/libc/include/machine/stdlib.h
new file mode 100644 (file)
index 0000000..fa3f3a1
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef        _MACHSTDLIB_H_
+#define        _MACHSTDLIB_H_
+
+/* place holder so platforms may add stdlib.h extensions */
+
+#endif /* _MACHSTDLIB_H_ */
+
+
index 5ccdda6..08a1425 100644 (file)
@@ -9,6 +9,9 @@
 #define __need_size_t
 #include <stddef.h>
 
+/* include any machine-specific extensions */
+#include <machine/malloc.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
index 00a9d1a..eb8f54d 100644 (file)
@@ -17,7 +17,7 @@ extern "C" {
 #include <stddef.h>
 
 #include <sys/reent.h>
-
+#include <machine/stdlib.h>
 #ifndef __STRICT_ANSI__
 #include <alloca.h>
 #endif
index 1c65b9f..4ddc19a 100644 (file)
@@ -7,6 +7,19 @@ INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS)
 noinst_LIBRARIES = lib.a
 
 lib_a_SOURCES = setjmp.S
+lib_a_LIBADD = @extra_objs@
+EXTRA_lib_a_SOURCES = @extra_sources@
+lib_a_DEPENDENCIES = @extra_objs@
 
-ACLOCAL_AMFLAGS = -I ../../..
+ACLOCAL_AMFLAGS = -I ../../.. 
+AM_CFLAGS = -I $(srcdir)/../../stdio
 CONFIG_STATUS_DEPENDENCIES = $(newlib_basedir)/configure.host
+
+VEC_MALLOC_COMPILE = $(COMPILE) -DINTERNAL_NEWLIB
+
+vec_reallocr.o: vec_mallocr.c
+       $(VEC_MALLOC_COMPILE) -DDEFINE_VECREALLOC -c $(srcdir)/vec_mallocr.c -o $@
+
+vec_callocr.o: vec_mallocr.c
+       $(VEC_MALLOC_COMPILE) -DDEFINE_VECCALLOC -c $(srcdir)/vec_mallocr.c -o $@
+
index ace6f06..d2721cb 100644 (file)
@@ -72,6 +72,8 @@ PACKAGE = @PACKAGE@
 RANLIB = @RANLIB@
 VERSION = @VERSION@
 aext = @aext@
+extra_objs = @extra_objs@
+extra_sources = @extra_sources@
 libm_machine_dir = @libm_machine_dir@
 machine_dir = @machine_dir@
 newlib_basedir = @newlib_basedir@
@@ -85,9 +87,15 @@ INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS)
 noinst_LIBRARIES = lib.a
 
 lib_a_SOURCES = setjmp.S
+lib_a_LIBADD = @extra_objs@
+EXTRA_lib_a_SOURCES = @extra_sources@
+lib_a_DEPENDENCIES = @extra_objs@
 
-ACLOCAL_AMFLAGS = -I ../../..
+ACLOCAL_AMFLAGS = -I ../../.. 
+AM_CFLAGS = -I $(srcdir)/../../stdio
 CONFIG_STATUS_DEPENDENCIES = $(newlib_basedir)/configure.host
+
+VEC_MALLOC_COMPILE = $(COMPILE) -DINTERNAL_NEWLIB
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 mkinstalldirs = $(SHELL) $(top_srcdir)/../../../../mkinstalldirs
 CONFIG_CLEAN_FILES = 
@@ -97,7 +105,6 @@ LIBRARIES =  $(noinst_LIBRARIES)
 DEFS = @DEFS@ -I. -I$(srcdir) 
 CPPFLAGS = @CPPFLAGS@
 LIBS = @LIBS@
-lib_a_LIBADD = 
 lib_a_OBJECTS =  setjmp.o
 CFLAGS = @CFLAGS@
 COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -110,7 +117,7 @@ DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
 
 TAR = gtar
 GZIP_ENV = --best
-SOURCES = $(lib_a_SOURCES)
+SOURCES = $(lib_a_SOURCES) $(EXTRA_lib_a_SOURCES)
 OBJECTS = $(lib_a_OBJECTS)
 
 all: all-redirect
@@ -316,6 +323,12 @@ mostlyclean-generic distclean-generic clean-generic \
 maintainer-clean-generic clean mostlyclean distclean maintainer-clean
 
 
+vec_reallocr.o: vec_mallocr.c
+       $(VEC_MALLOC_COMPILE) -DDEFINE_VECREALLOC -c $(srcdir)/vec_mallocr.c -o $@
+
+vec_callocr.o: vec_mallocr.c
+       $(VEC_MALLOC_COMPILE) -DDEFINE_VECCALLOC -c $(srcdir)/vec_mallocr.c -o $@
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
 .NOEXPORT:
index e55c232..15a7a2b 100755 (executable)
@@ -1440,6 +1440,17 @@ fi
 
 
 
+extra_objs=
+extra_sources=
+case $host in
+  powerpc*-*altivec*)
+       extra_objs="vfprintf.o vfscanf.o vec_malloc.o vec_calloc.o vec_free.o vec_realloc.o vec_reallocr.o vec_callocr.o"
+       extra_sources="vfprintf.c vfscanf.c vec_malloc.c vec_calloc.c vec_free.c vec_realloc.c vec_mallocr.c"
+       ;;
+esac
+
+
+
 trap '' 1 2 15
 cat > confcache <<\EOF
 # This file is a shell script that caches the results of configure
@@ -1623,6 +1634,8 @@ s%@aext@%$aext%g
 s%@libm_machine_dir@%$libm_machine_dir%g
 s%@machine_dir@%$machine_dir%g
 s%@sys_dir@%$sys_dir%g
+s%@extra_objs@%$extra_objs%g
+s%@extra_sources@%$extra_sources%g
 
 CEOF
 EOF
index 47b9eab..655c086 100644 (file)
@@ -9,4 +9,15 @@ AC_CONFIG_AUX_DIR(../../../..)
 
 NEWLIB_CONFIGURE(../../..)
 
+extra_objs=
+extra_sources=
+case $host in
+  powerpc*-*altivec*)
+       extra_objs="vfprintf.o vfscanf.o vec_malloc.o vec_calloc.o vec_free.o vec_realloc.o vec_reallocr.o vec_callocr.o"
+       extra_sources="vfprintf.c vfscanf.c vec_malloc.c vec_calloc.c vec_free.c vec_realloc.c vec_mallocr.c"
+       ;;
+esac
+AC_SUBST(extra_objs)
+AC_SUBST(extra_sources)
+
 AC_OUTPUT(Makefile)
diff --git a/newlib/libc/machine/powerpc/machine/malloc.h b/newlib/libc/machine/powerpc/machine/malloc.h
new file mode 100644 (file)
index 0000000..945a965
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef        _MACHMALLOC_H_
+#define        _MACHMALLOC_H_
+
+# if defined(__ALTIVEC__)
+
+_PTR    _EXFUN(vec_calloc,(size_t __nmemb, size_t __size));
+_PTR    _EXFUN(_vec_calloc_r,(struct _reent *, size_t __nmemb, size_t __size));
+_VOID   _EXFUN(vec_free,(_PTR));
+#define _vec_freer _freer
+_PTR    _EXFUN(vec_malloc,(size_t __size));
+#define _vec_mallocr _memalign_r
+_PTR    _EXFUN(vec_realloc,(_PTR __r, size_t __size));
+_PTR    _EXFUN(_vec_realloc_r,(struct _reent *, _PTR __r, size_t __size));
+
+# endif /* __ALTIVEC__ */
+
+
+#endif /* _MACHMALLOC_H_ */
+
+
diff --git a/newlib/libc/machine/powerpc/machine/stdlib.h b/newlib/libc/machine/powerpc/machine/stdlib.h
new file mode 100644 (file)
index 0000000..17e9dc3
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef        _MACHSTDLIB_H_
+#define        _MACHSTDLIB_H_
+
+#ifndef __STRICT_ANSI__
+
+# if defined(__ALTIVEC__)
+
+_PTR    _EXFUN(vec_calloc,(size_t __nmemb, size_t __size));
+_PTR    _EXFUN(_vec_calloc_r,(struct _reent *, size_t __nmemb, size_t __size));
+_VOID   _EXFUN(vec_free,(_PTR));
+#define _vec_freer _freer
+_PTR    _EXFUN(vec_malloc,(size_t __size));
+#define _vec_mallocr _memalign_r
+_PTR    _EXFUN(vec_realloc,(_PTR __r, size_t __size));
+_PTR    _EXFUN(_vec_realloc_r,(struct _reent *, _PTR __r, size_t __size));
+
+# endif /* __ALTIVEC__ */
+
+#endif /* !__STRICT_ANSI__ */
+
+
+#endif /* _MACHSTDLIB_H_ */
+
+
index c137691..ec3a443 100644 (file)
@@ -1,11 +1,17 @@
 /* This is a simple version of setjmp and longjmp for the PowerPC.
-   Ian Lance Taylor, Cygnus Support, 9 Feb 1994.  */
+   Ian Lance Taylor, Cygnus Support, 9 Feb 1994.  
+   Modified by Jeff Johnston, Red Hat Inc. 2 Oct 2001. */
 
 #include "ppc-asm.h"
 
 FUNC_START(setjmp)
+#ifdef __ALTIVEC__
+       addi    3,3,15          # align Altivec to 16 byte boundary
+       rlwinm  3,3,0,0,27
+#else
        addi    3,3,7           # align to 8 byte boundary
        rlwinm  3,3,0,0,28
+#endif
        stw     1,0(3)          # offset 0
        stwu    2,4(3)          # offset 4
        stwu    13,4(3)         # offset 8
@@ -56,14 +62,50 @@ FUNC_START(setjmp)
        /* This requires a total of 21 * 4 + 18 * 8 + 4 + 4 + 4
           bytes == 60 * 4 bytes == 240 bytes.  */
 
+#ifdef __ALTIVEC__
+       /* save Altivec vrsave and vr20-vr31 registers */
+       mfspr   4,256           # vrsave register
+       stwu    4,16(3)         # offset 248
+       addi    3,3,8
+       stvx    20,0,3          # offset 256
+       addi    3,3,16
+       stvx    21,0,3          # offset 272
+       addi    3,3,16
+       stvx    22,0,3          # offset 288
+       addi    3,3,16
+       stvx    23,0,3          # offset 304
+       addi    3,3,16
+       stvx    24,0,3          # offset 320
+       addi    3,3,16
+       stvx    25,0,3          # offset 336
+       addi    3,3,16
+       stvx    26,0,3          # offset 352
+       addi    3,3,16
+       stvx    27,0,3          # offset 368
+       addi    3,3,16
+       stvx    28,0,3          # offset 384
+       addi    3,3,16
+       stvx    29,0,3          # offset 400
+       addi    3,3,16
+       stvx    30,0,3          # offset 416
+       addi    3,3,16
+       stvx    31,0,3          # offset 432
+
+       /* This requires a total of 240 + 8 + 8 + 12 * 16 == 448 bytes. */
+#endif
        li      3,0
        blr
 FUNC_END(setjmp)
 
 
 FUNC_START(longjmp)
+#ifdef __ALTIVEC__
+       addi    3,3,15          # align Altivec to 16 byte boundary
+       rlwinm  3,3,0,0,27
+#else
        addi    3,3,7           # align to 8 byte boundary
        rlwinm  3,3,0,0,28
+#endif
        lwz     1,0(3)          # offset 0 
        lwzu    2,4(3)          # offset 4 
        lwzu    13,4(3)         # offset 8 
@@ -111,6 +153,36 @@ FUNC_START(longjmp)
        lfdu    31,8(3)         # offset 232
 #endif
 
+#ifdef __ALTIVEC__
+       /* restore Altivec vrsave and v20-v31 registers */
+       lwzu    5,16(3)         # offset 248
+       mtspr   256,5           # vrsave
+       addi    3,3,8
+       lvx     20,0,3          # offset 256
+       addi    3,3,16
+       lvx     21,0,3          # offset 272
+       addi    3,3,16
+       lvx     22,0,3          # offset 288
+       addi    3,3,16
+       lvx     23,0,3          # offset 304
+       addi    3,3,16
+       lvx     24,0,3          # offset 320
+       addi    3,3,16
+       lvx     25,0,3          # offset 336
+       addi    3,3,16
+       lvx     26,0,3          # offset 352
+       addi    3,3,16
+       lvx     27,0,3          # offset 368
+       addi    3,3,16
+       lvx     28,0,3          # offset 384
+       addi    3,3,16
+       lvx     29,0,3          # offset 400
+       addi    3,3,16
+       lvx     30,0,3          # offset 416
+       addi    3,3,16
+       lvx     31,0,3          # offset 432
+#endif
+
        mr.     3,4
        bclr+   4,2
        li      3,1
diff --git a/newlib/libc/machine/powerpc/vec_calloc.c b/newlib/libc/machine/powerpc/vec_calloc.c
new file mode 100644 (file)
index 0000000..5efe910
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+FUNCTION
+<<vec_calloc>>---allocate space for arrays
+
+INDEX
+       vec_calloc
+
+INDEX
+       _vec_calloc_r
+
+ANSI_SYNOPSIS
+       #include <stdlib.h>
+       void *vec_calloc(size_t <[n]>, size_t <[s]>);
+       void *vec_calloc_r(void *<[reent]>, size_t <n>, <size_t> <[s]>);
+       
+TRAD_SYNOPSIS
+       #include <stdlib.h>
+       char *vec_calloc(<[n]>, <[s]>)
+       size_t <[n]>, <[s]>;
+
+       char *_vec_calloc_r(<[reent]>, <[n]>, <[s]>)
+       char *<[reent]>;
+       size_t <[n]>;
+       size_t <[s]>;
+
+
+
+DESCRIPTION
+Use <<vec_calloc>> to request a block of memory sufficient to hold an
+array of <[n]> elements, each of which has size <[s]>.
+
+The memory allocated by <<vec_calloc>> comes out of the same memory pool
+used by <<vec_malloc>>, but the memory block is initialized to all zero
+bytes.  (To avoid the overhead of initializing the space, use
+<<vec_malloc>> instead.)
+
+The alternate function <<_vec_calloc_r>> is reentrant.
+The extra argument <[reent]> is a pointer to a reentrancy structure.
+
+RETURNS
+If successful, a pointer to the newly allocated space.
+
+If unsuccessful, <<NULL>>.
+
+PORTABILITY
+<<vec_calloc>> is an non-ANSI extension described in the AltiVec Programming
+Interface Manual.
+
+Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
+<<lseek>>, <<read>>, <<sbrk>>, <<write>>.
+*/
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef _REENT_ONLY
+
+_PTR
+_DEFUN (vec_calloc, (n, size),
+       size_t n _AND
+       size_t size)
+{
+  return _vec_calloc_r (_REENT, n, size);
+}
+
+#endif
diff --git a/newlib/libc/machine/powerpc/vec_free.c b/newlib/libc/machine/powerpc/vec_free.c
new file mode 100644 (file)
index 0000000..b55c52d
--- /dev/null
@@ -0,0 +1,15 @@
+/* vec_free.c - a wrapper for _free_r */
+#include <_ansi.h>
+#include <reent.h>
+#include <stdlib.h>
+
+#ifndef _REENT_ONLY
+
+void
+_DEFUN (vec_free, (aptr),
+        _PTR aptr)
+{
+  _free_r (_REENT, aptr);
+}
+
+#endif /* !_REENT_ONLY */
diff --git a/newlib/libc/machine/powerpc/vec_malloc.c b/newlib/libc/machine/powerpc/vec_malloc.c
new file mode 100644 (file)
index 0000000..6bcad59
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+FUNCTION
+<<vec_malloc>>, <<vec_realloc>>, <<vec_free>>---manage vector memory
+
+INDEX
+       vec_malloc
+INDEX
+       vec_realloc
+INDEX
+       vec_free
+INDEX
+       _vec_malloc_r
+INDEX
+       _vec_realloc_r
+INDEX
+       _vec_free_r
+
+ANSI_SYNOPSIS
+       #include <stdlib.h>
+       void *vec_malloc(size_t <[nbytes]>);
+       void *vec_realloc(void *<[aptr]>, size_t <[nbytes]>);
+       void vec_free(void *<[aptr]>);
+
+
+       void *_vec_malloc_r(void *<[reent]>, size_t <[nbytes]>);
+       void *_vec_realloc_r(void *<[reent]>, 
+                         void *<[aptr]>, size_t <[nbytes]>);
+       void _vec_free_r(void *<[reent]>, void *<[aptr]>);
+
+
+TRAD_SYNOPSIS
+       #include <stdlib.h>
+       char *vec_malloc(<[nbytes]>)
+       size_t <[nbytes]>;
+
+       char *vec_realloc(<[aptr]>, <[nbytes]>)
+       char *<[aptr]>;
+       size_t <[nbytes]>;
+
+       void vec_free(<[aptr]>)
+       char *<[aptr]>;
+
+       char *_vec_malloc_r(<[reent]>,<[nbytes]>)
+       char *<[reent]>;
+       size_t <[nbytes]>;
+
+       char *_vec_realloc_r(<[reent]>, <[aptr]>, <[nbytes]>)
+       char *<[reent]>;
+       char *<[aptr]>;
+       size_t <[nbytes]>;
+
+       void _vec_free_r(<[reent]>, <[aptr]>)
+       char *<[reent]>;
+       char *<[aptr]>;
+
+DESCRIPTION
+These functions manage a pool of system memory that is 16-byte aligned..
+
+Use <<vec_malloc>> to request allocation of an object with at least
+<[nbytes]> bytes of storage available and is 16-byte aligned.  If the space is 
+available, <<vec_malloc>> returns a pointer to a newly allocated block as its result.
+
+If you already have a block of storage allocated by <<vec_malloc>>, but
+you no longer need all the space allocated to it, you can make it
+smaller by calling <<vec_realloc>> with both the object pointer and the
+new desired size as arguments.  <<vec_realloc>> guarantees that the
+contents of the smaller object match the beginning of the original object.
+
+Similarly, if you need more space for an object, use <<vec_realloc>> to
+request the larger size; again, <<vec_realloc>> guarantees that the
+beginning of the new, larger object matches the contents of the
+original object.
+
+When you no longer need an object originally allocated by <<vec_malloc>>
+or <<vec_realloc>> (or the related function <<vec_calloc>>), return it to the
+memory storage pool by calling <<vec_free>> with the address of the object
+as the argument.  You can also use <<vec_realloc>> for this purpose by
+calling it with <<0>> as the <[nbytes]> argument.
+
+The alternate functions <<_vec_malloc_r>>, <<_vec_realloc_r>>, <<_vec_free_r>>,
+are reentrant versions.  The extra argument <[reent]> is a pointer to a reentrancy 
+structure.
+
+If you have multiple threads of execution which may call any of these
+routines, or if any of these routines may be called reentrantly, then
+you must provide implementations of the <<__vec_malloc_lock>> and
+<<__vec_malloc_unlock>> functions for your system.  See the documentation
+for those functions.
+
+These functions operate by calling the function <<_sbrk_r>> or
+<<sbrk>>, which allocates space.  You may need to provide one of these
+functions for your system.  <<_sbrk_r>> is called with a positive
+value to allocate more space, and with a negative value to release
+previously allocated space if it is no longer required.
+@xref{Stubs}.
+
+RETURNS
+<<vec_malloc>> returns a pointer to the newly allocated space, if
+successful; otherwise it returns <<NULL>>.  If your application needs
+to generate empty objects, you may use <<vec_malloc(0)>> for this purpose.
+
+<<vec_realloc>> returns a pointer to the new block of memory, or <<NULL>>
+if a new block could not be allocated.  <<NULL>> is also the result
+when you use `<<vec_realloc(<[aptr]>,0)>>' (which has the same effect as
+`<<vec_free(<[aptr]>)>>').  You should always check the result of
+<<vec_realloc>>; successful vec_reallocation is not guaranteed even when
+you request a smaller object.
+
+<<vec_free>> does not return a result.
+
+PORTABILITY
+<<vec_malloc>>, <<vec_realloc>>, and <<vec_free>> are all extensions
+specified in the AltiVec Programming Interface Manual.
+
+Supporting OS subroutines required: <<sbrk>>.  */
+
+#include <_ansi.h>
+#include <reent.h>
+#include <stdlib.h>
+#include <malloc.h>
+
+#ifndef _REENT_ONLY
+
+_PTR
+_DEFUN (vec_malloc, (nbytes),
+       size_t nbytes)          /* get a block */
+{
+  return _memalign_r (_REENT, 16, nbytes);
+}
+
+#endif
+
diff --git a/newlib/libc/machine/powerpc/vec_mallocr.c b/newlib/libc/machine/powerpc/vec_mallocr.c
new file mode 100644 (file)
index 0000000..c375c8b
--- /dev/null
@@ -0,0 +1,424 @@
+/* This code is based on mallocr.c written by Doug Lea which is released
+   to the public domain.  Any changes to libc/stdlib/mallocr.c
+   should be reflected here as well.    */
+
+/* Preliminaries */
+
+#ifndef __STD_C
+#ifdef __STDC__
+#define __STD_C     1
+#else
+#if __cplusplus
+#define __STD_C     1
+#else
+#define __STD_C     0
+#endif /*__cplusplus*/
+#endif /*__STDC__*/
+#endif /*__STD_C*/
+
+#ifndef Void_t
+#if __STD_C
+#define Void_t      void
+#else
+#define Void_t      char
+#endif
+#endif /*Void_t*/
+
+#if __STD_C
+#include <stddef.h>   /* for size_t */
+#else
+#include <sys/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/config.h>
+
+/*
+  In newlib, all the publically visible routines take a reentrancy
+  pointer.  We don't currently do anything much with it, but we do
+  pass it to the lock routine.
+ */
+
+#include <reent.h>
+#include <string.h>
+#include <malloc.h>
+
+#define MALLOC_LOCK __malloc_lock(reent_ptr)
+#define MALLOC_UNLOCK __malloc_unlock(reent_ptr)
+
+#ifdef SMALL_MEMORY
+#define malloc_getpagesize (128)
+#else
+#define malloc_getpagesize (4096)
+#endif
+
+#if __STD_C
+extern void __malloc_lock(struct _reent *);
+extern void __malloc_unlock(struct _reent *);
+#else
+extern void __malloc_lock();
+extern void __malloc_unlock();
+#endif
+
+#if __STD_C
+#define RARG struct _reent *reent_ptr,
+#define RONEARG struct _reent *reent_ptr
+#else
+#define RARG reent_ptr
+#define RONEARG reent_ptr
+#define RDECL struct _reent *reent_ptr;
+#endif
+
+#define RCALL reent_ptr,
+#define RONECALL reent_ptr
+
+/*
+   Define MALLOC_LOCK and MALLOC_UNLOCK to C expressions to run to
+   lock and unlock the malloc data structures.  MALLOC_LOCK may be
+   called recursively.
+ */
+
+#ifndef MALLOC_LOCK
+#define MALLOC_LOCK
+#endif
+
+#ifndef MALLOC_UNLOCK
+#define MALLOC_UNLOCK
+#endif
+
+/*
+  INTERNAL_SIZE_T is the word-size used for internal bookkeeping
+  of chunk sizes. On a 64-bit machine, you can reduce malloc
+  overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int'
+  at the expense of not being able to handle requests greater than
+  2^31. This limitation is hardly ever a concern; you are encouraged
+  to set this. However, the default version is the same as size_t.
+*/
+
+#ifndef INTERNAL_SIZE_T
+#define INTERNAL_SIZE_T size_t
+#endif
+
+/*
+  Following is needed on implementations whereby long > size_t.
+  The problem is caused because the code performs subtractions of
+  size_t values and stores the result in long values.  In the case
+  where long > size_t and the first value is actually less than
+  the second value, the resultant value is positive.  For example,
+  (long)(x - y) where x = 0 and y is 1 ends up being 0x00000000FFFFFFFF
+  which is 2*31 - 1 instead of 0xFFFFFFFFFFFFFFFF.  This is due to the
+  fact that assignment from unsigned to signed won't sign extend.
+*/
+
+#ifdef SIZE_T_SMALLER_THAN_LONG
+#define long_sub_size_t(x, y) ( (x < y) ? -((long)(y - x)) : (x - y) );
+#else
+#define long_sub_size_t(x, y) ( (long)(x - y) )
+#endif
+
+/*
+  REALLOC_ZERO_BYTES_FREES should be set if a call to
+  realloc with zero bytes should be the same as a call to free.
+  Some people think it should. Otherwise, since this malloc
+  returns a unique pointer for malloc(0), so does realloc(p, 0). 
+*/
+
+/* The following macros are only invoked with (2n+1)-multiples of
+   INTERNAL_SIZE_T units, with a positive integer n. This is exploited
+   for fast inline execution when n is small. */
+
+#define MALLOC_ZERO(charp, nbytes)                                            \
+do {                                                                          \
+  INTERNAL_SIZE_T mzsz = (nbytes);                                            \
+  if(mzsz <= 9*sizeof(mzsz)) {                                                \
+    INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp);                         \
+    if(mzsz >= 5*sizeof(mzsz)) {     *mz++ = 0;                               \
+                                     *mz++ = 0;                               \
+      if(mzsz >= 7*sizeof(mzsz)) {   *mz++ = 0;                               \
+                                     *mz++ = 0;                               \
+        if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0;                               \
+                                     *mz++ = 0; }}}                           \
+                                     *mz++ = 0;                               \
+                                     *mz++ = 0;                               \
+                                     *mz   = 0;                               \
+  } else memset((charp), 0, mzsz);                                            \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes)                                          \
+do {                                                                          \
+  INTERNAL_SIZE_T mcsz = (nbytes);                                            \
+  if(mcsz <= 9*sizeof(mcsz)) {                                                \
+    INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src);                        \
+    INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest);                       \
+    if(mcsz >= 5*sizeof(mcsz)) {     *mcdst++ = *mcsrc++;                     \
+                                     *mcdst++ = *mcsrc++;                     \
+      if(mcsz >= 7*sizeof(mcsz)) {   *mcdst++ = *mcsrc++;                     \
+                                     *mcdst++ = *mcsrc++;                     \
+        if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++;                     \
+                                     *mcdst++ = *mcsrc++; }}}                 \
+                                     *mcdst++ = *mcsrc++;                     \
+                                     *mcdst++ = *mcsrc++;                     \
+                                     *mcdst   = *mcsrc  ;                     \
+  } else memcpy(dest, src, mcsz);                                             \
+} while(0)
+
+#define vECCALLOc      _vec_calloc_r
+#define fREe           _free_r
+#define mEMALIGn       _memalign_r
+#define vECREALLOc     _vec_realloc_r
+#
+#if __STD_C
+
+Void_t* vECREALLOc(RARG Void_t*, size_t);
+Void_t* vECCALLOc(RARG size_t, size_t);
+#else
+Void_t* vECREALLOc();
+Void_t* vECCALLOc();
+#endif
+
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif
+
+/*
+  Type declarations
+*/
+
+struct malloc_chunk
+{
+  INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
+  INTERNAL_SIZE_T size;      /* Size in bytes, including overhead. */
+  struct malloc_chunk* fd;   /* double links -- used only if free. */
+  struct malloc_chunk* bk;
+};
+
+typedef struct malloc_chunk* mchunkptr;
+
+/*  sizes, alignments */
+
+#define SIZE_SZ                (sizeof(INTERNAL_SIZE_T))
+#define MALLOC_ALIGN           16
+#define MALLOC_ALIGNMENT       16
+#define MALLOC_ALIGN_MASK      (MALLOC_ALIGNMENT - 1)
+#define MINSIZE                (sizeof(struct malloc_chunk))
+
+/* conversion from malloc headers to user pointers, and back */
+
+#define chunk2mem(p)   ((Void_t*)((char*)(p) + 2*SIZE_SZ))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
+/* pad request bytes into a usable size */
+
+#define request2size(req) \
+ (((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \
+  (long)(MINSIZE + MALLOC_ALIGN_MASK)) ? ((MINSIZE + MALLOC_ALIGN_MASK) & ~(MALLOC_ALIGN_MASK)) : \
+   (((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK)))
+
+
+/* Check if m has acceptable alignment */
+
+#define aligned_OK(m)    (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0)
+
+/* 
+  Physical chunk operations  
+*/
+
+
+/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
+
+#define PREV_INUSE 0x1 
+
+/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
+
+#define IS_MMAPPED 0x2
+
+/* Bits to mask off when extracting size */
+
+#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)
+
+
+/* Ptr to next physical malloc_chunk. */
+
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))
+
+/* Ptr to previous physical malloc_chunk */
+
+#define prev_chunk(p)\
+   ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))
+
+
+/* Treat space at ptr + offset as a chunk */
+
+#define chunk_at_offset(p, s)  ((mchunkptr)(((char*)(p)) + (s)))
+
+
+\f
+
+/* 
+  Dealing with use bits 
+*/
+
+/* extract p's inuse bit */
+
+#define inuse(p)\
+((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)
+
+/* extract inuse bit of previous chunk */
+
+#define prev_inuse(p)  ((p)->size & PREV_INUSE)
+
+/* check for mmap()'ed chunk */
+
+#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
+
+/* set/clear chunk as in use without otherwise disturbing */
+
+#define set_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE
+
+#define clear_inuse(p)\
+((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)
+
+/* check/set/clear inuse bits in known places */
+
+#define inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
+
+#define set_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)
+
+#define clear_inuse_bit_at_offset(p, s)\
+ (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
+
+
+
+/* 
+  Dealing with size fields 
+*/
+
+/* Get size, ignoring use bits */
+
+#define chunksize(p)          ((p)->size & ~(SIZE_BITS))
+
+/* Set size at head, without disturbing its use bit */
+
+#define set_head_size(p, s)   ((p)->size = (((p)->size & PREV_INUSE) | (s)))
+
+/* Set size/use ignoring previous bits in header */
+
+#define set_head(p, s)        ((p)->size = (s))
+
+\f
+
+#ifdef DEFINE_VECREALLOC
+
+
+#if __STD_C
+Void_t* vECREALLOc(RARG Void_t* oldmem, size_t bytes)
+#else
+Void_t* vECREALLOc(RARG oldmem, bytes) RDECL Void_t* oldmem; size_t bytes;
+#endif
+{
+  INTERNAL_SIZE_T    nb;      /* padded request size */
+
+  mchunkptr oldp;             /* chunk corresponding to oldmem */
+  INTERNAL_SIZE_T    oldsize; /* its size */
+
+  mchunkptr newp;             /* chunk to return */
+  INTERNAL_SIZE_T    newsize; /* its size */
+  Void_t*   newmem;           /* corresponding user mem */
+
+  mchunkptr remainder;        /* holds split off extra space from newp */
+  INTERNAL_SIZE_T  remainder_size;   /* its size */
+
+#ifdef REALLOC_ZERO_BYTES_FREES
+  if (bytes == 0) { fREe(RCALL oldmem); return 0; }
+#endif
+
+
+  /* realloc of null is supposed to be same as malloc */
+  if (oldmem == 0) return mEMALIGn(RCALL 16, bytes);
+
+  MALLOC_LOCK;
+
+  newp    = oldp    = mem2chunk(oldmem);
+  newsize = oldsize = chunksize(oldp);
+
+  nb = request2size(bytes);
+
+  if ((long)(oldsize) < (long)(nb))  
+  {
+    /* Must allocate */
+
+    newmem = mEMALIGn (RCALL 16, bytes);
+
+    if (newmem == 0)  /* propagate failure */
+    {
+      MALLOC_UNLOCK;
+      return 0;
+    }
+
+    /* copy, free, and exit */
+    MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+    fREe(RCALL oldmem);
+    MALLOC_UNLOCK;
+    return newmem;
+  }
+
+  remainder_size = long_sub_size_t(newsize, nb);
+
+  if (remainder_size >= (long)MINSIZE) /* split off remainder */
+  {
+    remainder = chunk_at_offset(newp, nb);
+    set_head_size(newp, nb);
+    set_head(remainder, remainder_size | PREV_INUSE);
+    set_inuse_bit_at_offset(remainder, remainder_size);
+    fREe(RCALL chunk2mem(remainder)); /* let free() deal with it */
+  }
+  else
+  {
+    set_head_size(newp, newsize);
+    set_inuse_bit_at_offset(newp, newsize);
+  }
+
+  MALLOC_UNLOCK;
+  return chunk2mem(newp);
+}
+
+#endif /* DEFINE_VECREALLOC */
+\f
+
+#ifdef DEFINE_VECCALLOC
+
+/*
+
+  calloc calls malloc, then zeroes out the allocated chunk.
+
+*/
+
+#if __STD_C
+Void_t* vECCALLOc(RARG size_t n, size_t elem_size)
+#else
+Void_t* vECCALLOc(RARG n, elem_size) RDECL size_t n; size_t elem_size;
+#endif
+{
+  INTERNAL_SIZE_T sz = n * elem_size;
+
+  Void_t* mem;
+
+  mem = mEMALIGn (RCALL 16, sz);
+
+  if (mem == 0) 
+  {
+    return 0;
+  }
+
+  MALLOC_ZERO(mem, sz);
+  return mem;
+}
+
+#endif /* DEFINE_VECCALLOC */
+
diff --git a/newlib/libc/machine/powerpc/vec_realloc.c b/newlib/libc/machine/powerpc/vec_realloc.c
new file mode 100644 (file)
index 0000000..e192e39
--- /dev/null
@@ -0,0 +1,17 @@
+/* vec_realloc.c -- a wrapper for _vec_realloc_r.  */
+
+#include <_ansi.h>
+#include <reent.h>
+#include <stdlib.h>
+
+#ifndef _REENT_ONLY
+
+_PTR
+_DEFUN (vec_realloc, (ap, nbytes),
+       _PTR ap _AND
+       size_t nbytes)
+{
+  return _vec_realloc_r (_REENT, ap, nbytes);
+}
+
+#endif
diff --git a/newlib/libc/machine/powerpc/vfprintf.c b/newlib/libc/machine/powerpc/vfprintf.c
new file mode 100644 (file)
index 0000000..cf05429
--- /dev/null
@@ -0,0 +1,1195 @@
+/*
+FUNCTION
+<<vprintf>>, <<vfprintf>>, <<vsprintf>>---format argument list
+
+INDEX
+       vprintf
+INDEX
+       vfprintf
+INDEX
+       vsprintf
+INDEX
+       vsnprintf
+
+ANSI_SYNOPSIS
+       #include <stdio.h>
+       #include <stdarg.h>
+       int vprintf(const char *<[fmt]>, va_list <[list]>);
+       int vfprintf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>);
+       int vsprintf(char *<[str]>, const char *<[fmt]>, va_list <[list]>);
+       int vsnprintf(char *<[str]>, size_t <[size]>, const char *<[fmt]>, va_list <[list]>);
+
+       int _vprintf_r(void *<[reent]>, const char *<[fmt]>,
+                        va_list <[list]>);
+       int _vfprintf_r(void *<[reent]>, FILE *<[fp]>, const char *<[fmt]>,
+                        va_list <[list]>);
+       int _vsprintf_r(void *<[reent]>, char *<[str]>, const char *<[fmt]>,
+                        va_list <[list]>);
+       int _vsnprintf_r(void *<[reent]>, char *<[str]>, size_t <[size]>, const char *<[fmt]>,
+                        va_list <[list]>);
+
+TRAD_SYNOPSIS
+       #include <stdio.h>
+       #include <varargs.h>
+       int vprintf( <[fmt]>, <[list]>)
+       char *<[fmt]>;
+       va_list <[list]>;
+
+       int vfprintf(<[fp]>, <[fmt]>, <[list]>)
+       FILE *<[fp]>;
+       char *<[fmt]>;
+       va_list <[list]>;
+
+       int vsprintf(<[str]>, <[fmt]>, <[list]>)
+       char *<[str]>;
+       char *<[fmt]>;
+       va_list <[list]>;
+
+       int vsnprintf(<[str]>, <[size]>, <[fmt]>, <[list]>)
+       char *<[str]>;
+        size_t <[size]>;
+       char *<[fmt]>;
+       va_list <[list]>;
+
+       int _vprintf_r(<[reent]>, <[fmt]>, <[list]>)
+       char *<[reent]>;
+       char *<[fmt]>;
+       va_list <[list]>;
+
+       int _vfprintf_r(<[reent]>, <[fp]>, <[fmt]>, <[list]>)
+       char *<[reent]>;
+       FILE *<[fp]>;
+       char *<[fmt]>;
+       va_list <[list]>;
+
+       int _vsprintf_r(<[reent]>, <[str]>, <[fmt]>, <[list]>)
+       char *<[reent]>;
+       char *<[str]>;
+       char *<[fmt]>;
+       va_list <[list]>;
+
+       int _vsnprintf_r(<[reent]>, <[str]>, <[size]>, <[fmt]>, <[list]>)
+       char *<[reent]>;
+       char *<[str]>;
+        size_t <[size]>;
+       char *<[fmt]>;
+       va_list <[list]>;
+
+DESCRIPTION
+<<vprintf>>, <<vfprintf>>, <<vsprintf>> and <<vsnprintf>> are (respectively)
+variants of <<printf>>, <<fprintf>>, <<sprintf>> and <<snprintf>>.  They differ
+only in allowing their caller to pass the variable argument list as a
+<<va_list>> object (initialized by <<va_start>>) rather than directly
+accepting a variable number of arguments.
+
+RETURNS
+The return values are consistent with the corresponding functions:
+<<vsprintf>> returns the number of bytes in the output string,
+save that the concluding <<NULL>> is not counted.
+<<vprintf>> and <<vfprintf>> return the number of characters transmitted.
+If an error occurs, <<vprintf>> and <<vfprintf>> return <<EOF>>. No
+error returns occur for <<vsprintf>>.
+
+PORTABILITY
+ANSI C requires all three functions.
+
+Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
+<<lseek>>, <<read>>, <<sbrk>>, <<write>>.
+*/
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/*static char *sccsid = "from: @(#)vfprintf.c  5.50 (Berkeley) 12/16/92";*/
+static char *rcsid = "$Id$";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Actual printf innards.
+ *
+ * This code is large and complicated...
+ */
+
+#ifdef INTEGER_ONLY
+#define VFPRINTF vfiprintf
+#define _VFPRINTF_R _vfiprintf_r
+#else
+#define VFPRINTF vfprintf
+#define _VFPRINTF_R _vfprintf_r
+#ifndef NO_FLOATING_POINT
+#define FLOATING_POINT
+#endif
+#endif
+
+#define _NO_LONGLONG
+#if defined WANT_PRINTF_LONG_LONG && defined __GNUC__
+# undef _NO_LONGLONG
+#endif
+
+#include <_ansi.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <reent.h>
+#ifdef __ALTIVEC__
+#include <altivec.h>
+#endif
+
+#ifdef _HAVE_STDC
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include "local.h"
+#include "fvwrite.h"
+#include "vfieeefp.h"
+
+/* Currently a test is made to see if long double processing is warranted.
+   This could be changed in the future should the _ldtoa_r code be
+   preferred over _dtoa_r.  */
+#define _NO_LONGDBL
+#if defined WANT_IO_LONG_DBL && (LDBL_MANT_DIG > DBL_MANT_DIG)
+#undef _NO_LONGDBL
+#endif
+
+#ifdef __ALTIVEC__
+typedef union
+{
+  vector int v;
+  float f[4];
+  int   i[16 / sizeof(int)];
+  long  l[4];
+  short s[8];
+  char  c[16];
+} vec_16_byte_union;
+#endif /* __ALTIVEC__ */
+
+/*
+ * Flush out all the vectors defined by the given uio,
+ * then reset it so that it can be reused.
+ */
+static int
+__sprint(fp, uio)
+       FILE *fp;
+       register struct __suio *uio;
+{
+       register int err;
+
+       if (uio->uio_resid == 0) {
+               uio->uio_iovcnt = 0;
+               return (0);
+       }
+       err = __sfvwrite(fp, uio);
+       uio->uio_resid = 0;
+       uio->uio_iovcnt = 0;
+       return (err);
+}
+
+/*
+ * Helper function for `fprintf to unbuffered unix file': creates a
+ * temporary buffer.  We only work on write-only files; this avoids
+ * worries about ungetc buffers and so forth.
+ */
+static int
+__sbprintf(fp, fmt, ap)
+       register FILE *fp;
+       const char *fmt;
+       va_list ap;
+{
+       int ret;
+       FILE fake;
+       unsigned char buf[BUFSIZ];
+
+       /* copy the important variables */
+       fake._data = fp->_data;
+       fake._flags = fp->_flags & ~__SNBF;
+       fake._file = fp->_file;
+       fake._cookie = fp->_cookie;
+       fake._write = fp->_write;
+
+       /* set up the buffer */
+       fake._bf._base = fake._p = buf;
+       fake._bf._size = fake._w = sizeof(buf);
+       fake._lbfsize = 0;      /* not actually used, but Just In Case */
+
+       /* do the work, then copy any error status */
+       ret = VFPRINTF(&fake, fmt, ap);
+       if (ret >= 0 && fflush(&fake))
+               ret = EOF;
+       if (fake._flags & __SERR)
+               fp->_flags |= __SERR;
+       return (ret);
+}
+
+
+#ifdef FLOATING_POINT
+#include <locale.h>
+#include <math.h>
+#include "floatio.h"
+
+#define        BUF             (MAXEXP+MAXFRACT+1)     /* + decimal point */
+#define        DEFPREC         6
+
+#ifdef _NO_LONGDBL
+static char *cvt _PARAMS((struct _reent *, double, int, int, char *, int *, int, int *));
+#else
+static char *cvt _PARAMS((struct _reent *, _LONG_DOUBLE, int, int, char *, int *, int, int *));
+extern int  _ldcheck _PARAMS((_LONG_DOUBLE *));
+#endif
+
+static int exponent _PARAMS((char *, int, int));
+
+#else /* no FLOATING_POINT */
+
+#define        BUF             40
+
+#endif /* FLOATING_POINT */
+
+
+/*
+ * Macros for converting digits to letters and vice versa
+ */
+#define        to_digit(c)     ((c) - '0')
+#define is_digit(c)    ((unsigned)to_digit(c) <= 9)
+#define        to_char(n)      ((n) + '0')
+
+/*
+ * Flags used during conversion.
+ */
+#define        ALT             0x001           /* alternate form */
+#define        HEXPREFIX       0x002           /* add 0x or 0X prefix */
+#define        LADJUST         0x004           /* left adjustment */
+#define        LONGDBL         0x008           /* long double */
+#define        LONGINT         0x010           /* long integer */
+#ifndef _NO_LONGLONG
+#define        QUADINT         0x020           /* quad integer */
+#else /* ifdef _NO_LONGLONG, make QUADINT equivalent to LONGINT, so
+        that %lld behaves the same as %ld, not as %d, as expected if:
+        sizeof (long long) = sizeof long > sizeof int  */
+#define        QUADINT         LONGINT
+#endif
+#define        SHORTINT        0x040           /* short integer */
+#define        ZEROPAD         0x080           /* zero (as opposed to blank) pad */
+#define FPT            0x100           /* Floating point number */
+#define VECTOR         0x200           /* vector */
+
+int 
+_DEFUN (VFPRINTF, (fp, fmt0, ap),
+       FILE * fp _AND
+       _CONST char *fmt0 _AND
+       va_list ap)
+{
+  CHECK_INIT (fp);
+  return _VFPRINTF_R (fp->_data, fp, fmt0, ap);
+}
+
+int 
+_DEFUN (_VFPRINTF_R, (data, fp, fmt0, ap),
+       struct _reent *data _AND
+       FILE * fp _AND
+       _CONST char *fmt0 _AND
+       va_list ap)
+{
+       register char *fmt;     /* format string */
+       register int ch;        /* character from fmt */
+       register int n, m;      /* handy integers (short term usage) */
+       register char *cp;      /* handy char pointer (short term usage) */
+       register struct __siov *iovp;/* for PRINT macro */
+       register int flags;     /* flags as above */
+       int ret;                /* return value accumulator */
+       int width;              /* width from format (%8d), or 0 */
+       int prec;               /* precision from format (%.3d), or -1 */
+       char sign;              /* sign prefix (' ', '+', '-', or \0) */
+       char old_sign;          /* saved value of sign when looping for vectors */
+       wchar_t wc;
+#ifdef FLOATING_POINT
+       char *decimal_point = localeconv()->decimal_point;
+       char softsign;          /* temporary negative sign for floats */
+#ifdef _NO_LONGDBL
+       union { int i; double d; } _double_ = {0};
+       #define _fpvalue (_double_.d)
+#else
+       union { int i; _LONG_DOUBLE ld; } _long_double_ = {0};
+       #define _fpvalue (_long_double_.ld)
+       int tmp;  
+#endif
+       int expt;               /* integer value of exponent */
+       int expsize = 0;        /* character count for expstr */
+       int ndig;               /* actual number of digits returned by cvt */
+       char expstr[7];         /* buffer for exponent string */
+#endif
+
+#ifndef _NO_LONGLONG
+#define        quad_t    long long
+#define        u_quad_t  unsigned long long
+#endif
+
+#ifndef _NO_LONGLONG
+       u_quad_t _uquad;        /* integer arguments %[diouxX] */
+#else
+       u_long _uquad;
+#endif
+       enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
+       int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
+       int realsz;             /* field size expanded by dprec */
+       int size;               /* size of converted field or string */
+       char *xdigs = NULL;     /* digits for [xX] conversion */
+#define NIOV 8
+       struct __suio uio;      /* output information: summary */
+       struct __siov iov[NIOV];/* ... and individual io vectors */
+       char buf[BUF];          /* space for %c, %[diouxX], %[eEfgG] */
+       char ox[2];             /* space for 0x hex-prefix */
+#ifdef __ALTIVEC__
+       char vec_sep;           /* vector separator char */
+       int vec_print_count;    /* number of vector chunks remaining */
+       vec_16_byte_union vec_tmp;
+#endif /* __ALTIVEC__ */ 
+        int state = 0;          /* mbtowc calls from library must not change state */
+
+       /*
+        * Choose PADSIZE to trade efficiency vs. size.  If larger printf
+        * fields occur frequently, increase PADSIZE and make the initialisers
+        * below longer.
+        */
+#define        PADSIZE 16              /* pad chunk size */
+       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'};
+
+       /*
+        * BEWARE, these `goto error' on error, and PAD uses `n'.
+        */
+#define        PRINT(ptr, len) { \
+       iovp->iov_base = (ptr); \
+       iovp->iov_len = (len); \
+       uio.uio_resid += (len); \
+       iovp++; \
+       if (++uio.uio_iovcnt >= NIOV) { \
+               if (__sprint(fp, &uio)) \
+                       goto error; \
+               iovp = iov; \
+       } \
+}
+#define        PAD(howmany, with) { \
+       if ((n = (howmany)) > 0) { \
+               while (n > PADSIZE) { \
+                       PRINT(with, PADSIZE); \
+                       n -= PADSIZE; \
+               } \
+               PRINT(with, n); \
+       } \
+}
+#define        FLUSH() { \
+       if (uio.uio_resid && __sprint(fp, &uio)) \
+               goto error; \
+       uio.uio_iovcnt = 0; \
+       iovp = iov; \
+}
+
+#ifdef __ALTIVEC__
+#define GET_SHORT(ap) \
+       (flags&VECTOR ? \
+           (vec_print_count < 8 ? (short)vec_tmp.s[8 - vec_print_count] : \
+               (vec_tmp.v = va_arg(ap, vector int), (short)vec_tmp.s[0])) : \
+           (short)va_arg(ap, int))
+#define GET_USHORT(ap) \
+       (flags&VECTOR ? \
+           (vec_print_count < 8 ? (u_short)vec_tmp.s[8 - vec_print_count] : \
+               (vec_tmp.v = va_arg(ap, vector int), (u_short)vec_tmp.s[0])) : \
+           (u_short)va_arg(ap, int))
+
+#define GET_LONG(ap) \
+       (flags&VECTOR ? \
+           (vec_print_count < 4 ? (long)vec_tmp.l[4 - vec_print_count] : \
+               (vec_tmp.v = va_arg(ap, vector int), vec_tmp.l[0])) : \
+           va_arg(ap, long int))
+#define GET_ULONG(ap) \
+       (flags&VECTOR ? \
+           (vec_print_count < 4 ? (u_long)vec_tmp.l[4 - vec_print_count] : \
+               (vec_tmp.v = va_arg(ap, vector int), (u_long)vec_tmp.l[0])) : \
+           (u_long)va_arg(ap, unsigned long int))
+
+#define GET_INT(ap) \
+       (flags&VECTOR ? \
+           (vec_print_count < (16 / sizeof(int)) ? \
+                vec_tmp.i[16 / sizeof(int) - vec_print_count] : \
+               (vec_tmp.v = va_arg(ap, vector int), vec_tmp.i[0])) : \
+           va_arg(ap, int))
+#define GET_UINT(ap) \
+       (flags&VECTOR ? \
+           (vec_print_count < (16 / sizeof(int)) ? \
+                (u_int)vec_tmp.i[16 / sizeof(int) - vec_print_count] : \
+               (vec_tmp.v = va_arg(ap, vector int), (u_int)vec_tmp.i[0])) : \
+           (u_int)va_arg(ap, unsigned int))
+#else /* !__ALTIVEC__ */
+#define GET_SHORT(ap) ((short)va_arg(ap, int))
+#define GET_USHORT(ap) ((u_short)va_arg(ap, int))
+#define GET_LONG(ap) (va_arg(ap, long int))
+#define GET_ULONG(ap) ((u_long)va_arg(ap, unsigned long int))
+#define GET_INT(ap) ((int)va_arg(ap, int))
+#define GET_UINT(ap) ((u_int)va_arg(ap, unsigned int))
+#endif /* !__ALTIVEC__ */
+
+#ifndef _NO_LONGLONG
+#define        SARG() \
+       (flags&QUADINT ? va_arg(ap, quad_t) : \
+           flags&LONGINT ? GET_LONG(ap) : \
+           flags&SHORTINT ? (long)GET_SHORT(ap) : \
+           (long)GET_INT(ap))
+#define        UARG() \
+       (flags&QUADINT ? va_arg(ap, u_quad_t) : \
+           flags&LONGINT ? GET_ULONG(ap) : \
+           flags&SHORTINT ? (u_long)GET_USHORT(ap) : \
+           (u_long)GET_UINT(ap))
+#else
+#define        SARG() \
+       (flags&LONGINT ? GET_LONG(ap) : \
+           flags&SHORTINT ? (long)GET_SHORT(ap) : \
+           (long)GET_INT(ap))
+#define        UARG() \
+       (flags&LONGINT ? GET_ULONG(ap) : \
+           flags&SHORTINT ? (u_long)GET_USHORT(ap) : \
+           (u_long)GET_UINT(ap))
+#endif
+
+       /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
+       if (cantwrite(fp))
+               return (EOF);
+
+       /* optimise fprintf(stderr) (and other unbuffered Unix files) */
+       if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
+           fp->_file >= 0)
+               return (__sbprintf(fp, fmt0, ap));
+
+       fmt = (char *)fmt0;
+       uio.uio_iov = iovp = iov;
+       uio.uio_resid = 0;
+       uio.uio_iovcnt = 0;
+       ret = 0;
+
+       /*
+        * Scan the format for conversions (`%' character).
+        */
+       for (;;) {
+               cp = fmt;
+               while ((n = _mbtowc_r(_REENT, &wc, fmt, MB_CUR_MAX, &state)) > 0) {
+                       fmt += n;
+                       if (wc == '%') {
+                               fmt--;
+                               break;
+                       }
+               }
+               if ((m = fmt - cp) != 0) {
+                       PRINT(cp, m);
+                       ret += m;
+               }
+               if (n <= 0)
+                       goto done;
+               fmt++;          /* skip over '%' */
+
+               flags = 0;
+               dprec = 0;
+               width = 0;
+               prec = -1;
+               sign = '\0';
+               old_sign = '\0';
+#ifdef __ALTIVEC__
+               vec_print_count = 0;
+               vec_sep = ' ';
+#endif /* __ALTIVEC__ */
+
+rflag:         ch = *fmt++;
+reswitch:      switch (ch) {
+               case ' ':
+                       /*
+                        * ``If the space and + flags both appear, the space
+                        * flag will be ignored.''
+                        *      -- ANSI X3J11
+                        */
+                       if (!sign)
+                               sign = ' ';
+                       goto rflag;
+               case '#':
+                       flags |= ALT;
+                       goto rflag;
+               case '*':
+                       /*
+                        * ``A negative field width argument is taken as a
+                        * - flag followed by a positive field width.''
+                        *      -- ANSI X3J11
+                        * They don't exclude field widths read from args.
+                        */
+                       if ((width = va_arg(ap, int)) >= 0)
+                               goto rflag;
+                       width = -width;
+                       /* FALLTHROUGH */
+               case '-':
+                       flags |= LADJUST;
+                       goto rflag;
+               case '+':
+                       sign = '+';
+                       goto rflag;
+#ifdef __ALTIVEC__
+               case ',':
+               case ';':
+               case ':':
+               case '_':
+                       vec_sep = ch;
+                       goto rflag;
+#endif /* __ALTIVEC__ */
+               case '.':
+                       if ((ch = *fmt++) == '*') {
+                               n = va_arg(ap, int);
+                               prec = n < 0 ? -1 : n;
+                               goto rflag;
+                       }
+                       n = 0;
+                       while (is_digit(ch)) {
+                               n = 10 * n + to_digit(ch);
+                               ch = *fmt++;
+                       }
+                       prec = n < 0 ? -1 : n;
+                       goto reswitch;
+               case '0':
+                       /*
+                        * ``Note that 0 is taken as a flag, not as the
+                        * beginning of a field width.''
+                        *      -- ANSI X3J11
+                        */
+                       flags |= ZEROPAD;
+                       goto rflag;
+               case '1': case '2': case '3': case '4':
+               case '5': case '6': case '7': case '8': case '9':
+                       n = 0;
+                       do {
+                               n = 10 * n + to_digit(ch);
+                               ch = *fmt++;
+                       } while (is_digit(ch));
+                       width = n;
+                       goto reswitch;
+#ifdef FLOATING_POINT
+               case 'L':
+                       flags &= ~VECTOR;
+                       flags |= LONGDBL;
+                       goto rflag;
+#endif
+               case 'h':
+                       flags |= SHORTINT;
+#ifdef __ALTIVEC__
+                       if (flags & VECTOR)
+                         vec_print_count = 8;
+#endif
+                       goto rflag;
+               case 'l':
+                       if (*fmt == 'l') {
+                               fmt++;
+                               flags |= QUADINT;
+                               flags &= ~VECTOR;
+                       } else {
+                               flags |= LONGINT;
+#ifdef __ALTIVEC__
+                               if (flags & VECTOR)
+                                 vec_print_count = 4;
+#endif
+                       }
+                       goto rflag;
+#ifdef __ALTIVEC__
+               case 'v':
+                       flags |= VECTOR;
+                       vec_print_count = (flags & SHORTINT) ? 8 : 
+                         ((flags & LONGINT) ? 4 : (16 / sizeof(int)));
+                       goto rflag;
+#endif
+                case 'q':
+                       flags &= ~VECTOR;
+                       flags |= QUADINT;
+                       goto rflag;
+               case 'c':
+#ifdef __ALTIVEC__
+                       if (flags & VECTOR)
+                         {
+                           int k;
+                           vec_16_byte_union tmp;
+                           tmp.v = va_arg(ap, vector int);
+                           cp = buf;
+                           for (k = 0; k < 15; ++k)
+                             {
+                               *cp++ = tmp.c[k];
+                               if (vec_sep != ' ')
+                                 *cp++ = vec_sep;
+                             }
+                           *cp++ = tmp.c[15];
+                           size = cp - buf;
+                           cp = buf;
+                           vec_print_count = 0;
+                         }
+                       else
+#endif /* __ALTIVEC__ */
+                         {
+                           *(cp = buf) = va_arg(ap, int);
+                           size = 1;
+                         }
+                       sign = '\0';
+                       break;
+               case 'D':
+                       flags |= LONGINT;
+                       /*FALLTHROUGH*/
+               case 'd':
+               case 'i':
+                       _uquad = SARG();
+#ifndef _NO_LONGLONG
+                       if ((quad_t)_uquad < 0)
+#else
+                       if ((long) _uquad < 0)
+#endif
+                       {
+
+                               _uquad = -_uquad;
+                               old_sign = sign;
+                               sign = '-';
+                       }
+                       base = DEC;
+                       goto number;
+#ifdef FLOATING_POINT
+               case 'e':
+               case 'E':
+               case 'f':
+               case 'g':
+               case 'G':
+                       if (prec == -1) {
+                               prec = DEFPREC;
+                       } else if ((ch == 'g' || ch == 'G') && prec == 0) {
+                               prec = 1;
+                       }
+
+#ifdef _NO_LONGDBL
+                       if (flags & LONGDBL) {
+                               _fpvalue = (double) va_arg(ap, _LONG_DOUBLE);
+#ifdef __ALTIVEC__
+                       } else if (flags & VECTOR) {
+                               if (vec_print_count == 4)
+                                 vec_tmp.v = va_arg(ap, vector int);
+                               _fpvalue = (double)vec_tmp.f[4 - vec_print_count];
+#endif /* __ALTIVEC__ */
+                       } else {
+                               _fpvalue = va_arg(ap, double);
+                       }
+
+                       /* do this before tricky precision changes */
+                       if (isinf(_fpvalue)) {
+                               if (_fpvalue < 0)
+                                 {
+                                   old_sign = sign;
+                                   sign = '-';
+                                 }
+                                   
+                               cp = "Inf";
+                               size = 3;
+                               break;
+                       }
+                       if (isnan(_fpvalue)) {
+                               cp = "NaN";
+                               size = 3;
+                               break;
+                       }
+
+#else /* !_NO_LONGDBL */
+                       
+                       if (flags & LONGDBL) {
+                               _fpvalue = va_arg(ap, _LONG_DOUBLE);
+#ifdef __ALTIVEC__
+                       } else if (flags & VECTOR) {
+                               if (vec_print_count == 4)
+                                 vec_tmp.v = va_arg(ap, vector int);
+                               _fpvalue = (_LONG_DOUBLE)k.f[4 - vec_print_count];
+#endif /* __ALTIVEC__ */
+                       } else {
+                               _fpvalue = (_LONG_DOUBLE)va_arg(ap, double);
+                       }
+
+                       /* do this before tricky precision changes */
+                       tmp = _ldcheck (&_fpvalue);
+                       if (tmp == 2) {
+                               if (_fpvalue < 0)
+                                 {
+                                   old_sign = sign;
+                                   sign = '-';
+                                 }
+                               cp = "Inf";
+                               size = 3;
+                               break;
+                       }
+                       if (tmp == 1) {
+                               cp = "NaN";
+                               size = 3;
+                               break;
+                       }
+#endif /* !_NO_LONGDBL */
+
+                       flags |= FPT;
+
+                       cp = cvt(data, _fpvalue, prec, flags, &softsign,
+                               &expt, ch, &ndig);
+
+                       if (ch == 'g' || ch == 'G') {
+                               if (expt <= -4 || expt > prec)
+                                       ch = (ch == 'g') ? 'e' : 'E';
+                               else
+                                       ch = 'g';
+                       } 
+                       if (ch <= 'e') {        /* 'e' or 'E' fmt */
+                               --expt;
+                               expsize = exponent(expstr, expt, ch);
+                               size = expsize + ndig;
+                               if (ndig > 1 || flags & ALT)
+                                       ++size;
+                       } else if (ch == 'f') {         /* f fmt */
+                               if (expt > 0) {
+                                       size = expt;
+                                       if (prec || flags & ALT)
+                                               size += prec + 1;
+                               } else  /* "0.X" */
+                                       size = prec + 2;
+                       } else if (expt >= ndig) {      /* fixed g fmt */
+                               size = expt;
+                               if (flags & ALT)
+                                       ++size;
+                       } else
+                               size = ndig + (expt > 0 ?
+                                       1 : 2 - expt);
+
+                       if (softsign)
+                         {
+                           old_sign = sign;
+                           sign = '-';
+                         }
+                       break;
+#endif /* FLOATING_POINT */
+               case 'n':
+#ifndef _NO_LONGLONG
+                       flags &= ~VECTOR;
+                       if (flags & QUADINT)
+                               *va_arg(ap, quad_t *) = ret;
+                       else 
+#endif
+                       if (flags & LONGINT)
+                               *va_arg(ap, long *) = ret;
+                       else if (flags & SHORTINT)
+                               *va_arg(ap, short *) = ret;
+                       else
+                               *va_arg(ap, int *) = ret;
+                       continue;       /* no output */
+               case 'O':
+                       flags |= LONGINT;
+                       /*FALLTHROUGH*/
+               case 'o':
+                       _uquad = UARG();
+                       base = OCT;
+                       goto nosign;
+               case 'p':
+                       /*
+                        * ``The argument shall be a pointer to void.  The
+                        * value of the pointer is converted to a sequence
+                        * of printable characters, in an implementation-
+                        * defined manner.''
+                        *      -- ANSI X3J11
+                        */
+                       /* NOSTRICT */
+                       flags &= ~VECTOR;
+                       _uquad = (u_long)(unsigned _POINTER_INT)va_arg(ap, void *);
+                       base = HEX;
+                       xdigs = "0123456789abcdef";
+                       flags |= HEXPREFIX;
+                       ch = 'x';
+                       goto nosign;
+               case 's':
+                       flags &= ~VECTOR;
+                       if ((cp = va_arg(ap, char *)) == NULL)
+                               cp = "(null)";
+                       if (prec >= 0) {
+                               /*
+                                * can't use strlen; can only look for the
+                                * NUL in the first `prec' characters, and
+                                * strlen() will go further.
+                                */
+                               char *p = memchr(cp, 0, prec);
+
+                               if (p != NULL) {
+                                       size = p - cp;
+                                       if (size > prec)
+                                               size = prec;
+                               } else
+                                       size = prec;
+                       } else
+                               size = strlen(cp);
+                       sign = '\0';
+                       break;
+               case 'U':
+                       flags |= LONGINT;
+                       /*FALLTHROUGH*/
+               case 'u':
+                       _uquad = UARG();
+                       base = DEC;
+                       goto nosign;
+               case 'X':
+                       xdigs = "0123456789ABCDEF";
+                       goto hex;
+               case 'x':
+                       xdigs = "0123456789abcdef";
+hex:                   _uquad = UARG();
+                       base = HEX;
+                       /* leading 0x/X only if non-zero */
+                       if (flags & ALT && _uquad != 0)
+                               flags |= HEXPREFIX;
+
+                       /* unsigned conversions */
+nosign:                        sign = '\0';
+                       /*
+                        * ``... diouXx conversions ... if a precision is
+                        * specified, the 0 flag will be ignored.''
+                        *      -- ANSI X3J11
+                        */
+number:                        if ((dprec = prec) >= 0)
+                               flags &= ~ZEROPAD;
+
+                       /*
+                        * ``The result of converting a zero value with an
+                        * explicit precision of zero is no characters.''
+                        *      -- ANSI X3J11
+                        */
+                       cp = buf + BUF;
+                       if (_uquad != 0 || prec != 0) {
+                               /*
+                                * Unsigned mod is hard, and unsigned mod
+                                * by a constant is easier than that by
+                                * a variable; hence this switch.
+                                */
+                               switch (base) {
+                               case OCT:
+                                       do {
+                                               *--cp = to_char(_uquad & 7);
+                                               _uquad >>= 3;
+                                       } while (_uquad);
+                                       /* handle octal leading 0 */
+                                       if (flags & ALT && *cp != '0')
+                                               *--cp = '0';
+                                       break;
+
+                               case DEC:
+                                       /* many numbers are 1 digit */
+                                       while (_uquad >= 10) {
+                                               *--cp = to_char(_uquad % 10);
+                                               _uquad /= 10;
+                                       }
+                                       *--cp = to_char(_uquad);
+                                       break;
+
+                               case HEX:
+                                       do {
+                                               *--cp = xdigs[_uquad & 15];
+                                               _uquad >>= 4;
+                                       } while (_uquad);
+                                       break;
+
+                               default:
+                                       cp = "bug in vfprintf: bad base";
+                                       size = strlen(cp);
+                                       goto skipsize;
+                               }
+                       }
+                       /*
+                       * ...result is to be converted to an 'alternate form'.
+                       * For o conversion, it increases the precision to force
+                       * the first digit of the result to be a zero."
+                       *     -- ANSI X3J11
+                       *
+                       * To demonstrate this case, compile and run:
+                        *    printf ("%#.0o",0);
+                       */
+                       else if (base == OCT && (flags & ALT))
+                         *--cp = '0';
+
+                       size = buf + BUF - cp;
+               skipsize:
+                       break;
+               default:        /* "%?" prints ?, unless ? is NUL */
+                       flags &= ~VECTOR;
+                       if (ch == '\0')
+                               goto done;
+                       /* pretend it was %c with argument ch */
+                       cp = buf;
+                       *cp = ch;
+                       size = 1;
+                       sign = '\0';
+                       break;
+               }
+
+               /*
+                * All reasonable formats wind up here.  At this point, `cp'
+                * points to a string which (if not flags&LADJUST) should be
+                * padded out to `width' places.  If flags&ZEROPAD, it should
+                * first be prefixed by any sign or other prefix; otherwise,
+                * it should be blank padded before the prefix is emitted.
+                * After any left-hand padding and prefixing, emit zeroes
+                * required by a decimal [diouxX] precision, then print the
+                * string proper, then emit zeroes required by any leftover
+                * floating precision; finally, if LADJUST, pad with blanks.
+                *
+                * Compute actual size, so we know how much to pad.
+                * size excludes decimal prec; realsz includes it.
+                */
+               realsz = dprec > size ? dprec : size;
+               if (sign)
+                       realsz++;
+               else if (flags & HEXPREFIX)
+                       realsz+= 2;
+
+               /* right-adjusting blank padding */
+               if ((flags & (LADJUST|ZEROPAD)) == 0)
+                       PAD(width - realsz, blanks);
+
+               /* prefix */
+               if (sign) {
+                       PRINT(&sign, 1);
+               } else if (flags & HEXPREFIX) {
+                       ox[0] = '0';
+                       ox[1] = ch;
+                       PRINT(ox, 2);
+               }
+
+               /* right-adjusting zero padding */
+               if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
+                       PAD(width - realsz, zeroes);
+
+               /* leading zeroes from decimal precision */
+               PAD(dprec - size, zeroes);
+
+               /* the string or number proper */
+#ifdef FLOATING_POINT
+               if ((flags & FPT) == 0) {
+                               PRINT(cp, size);
+               } else {        /* glue together f_p fragments */
+                       if (ch >= 'f') {        /* 'f' or 'g' */
+                               if (_fpvalue == 0) {
+                                       /* kludge for __dtoa irregularity */
+                                       PRINT("0", 1);
+                                       if (expt < ndig || (flags & ALT) != 0) {
+                                               PRINT(decimal_point, 1);
+                                               PAD(ndig - 1, zeroes);
+                                       }
+                               } else if (expt <= 0) {
+                                       PRINT("0", 1);
+                                       if(expt || ndig) {
+                                               PRINT(decimal_point, 1);
+                                               PAD(-expt, zeroes);
+                                               PRINT(cp, ndig);
+                                       }
+                               } else if (expt >= ndig) {
+                                       PRINT(cp, ndig);
+                                       PAD(expt - ndig, zeroes);
+                                       if (flags & ALT)
+                                               PRINT(".", 1);
+                               } else {
+                                       PRINT(cp, expt);
+                                       cp += expt;
+                                       PRINT(".", 1);
+                                       PRINT(cp, ndig-expt);
+                               }
+                       } else {        /* 'e' or 'E' */
+                               if (ndig > 1 || flags & ALT) {
+                                       ox[0] = *cp++;
+                                       ox[1] = '.';
+                                       PRINT(ox, 2);
+                                       if (_fpvalue) {
+                                               PRINT(cp, ndig-1);
+                                       } else  /* 0.[0..] */
+                                               /* __dtoa irregularity */
+                                               PAD(ndig - 1, zeroes);
+                               } else  /* XeYYY */
+                                       PRINT(cp, 1);
+                               PRINT(expstr, expsize);
+                       }
+               }
+#else
+               PRINT(cp, size);
+#endif
+               /* left-adjusting padding (always blank) */
+               if (flags & LADJUST)
+                       PAD(width - realsz, blanks);
+
+               /* finally, adjust ret */
+               ret += width > realsz ? width : realsz;
+
+#ifdef __ALTIVEC__             
+               if ((flags & VECTOR) && vec_print_count-- > 1)
+                 {
+                   /* add vector separator */
+                   if (ch != 'c' || vec_sep != ' ')
+                     {
+                       PRINT(&vec_sep, 1);
+                       ret += 1;
+                     }
+                   FLUSH();
+                   sign = old_sign;
+                   goto reswitch;
+                 }
+#endif /* __ALTIVEC__ */
+               FLUSH();        /* copy out the I/O vectors */
+       }
+done:
+       FLUSH();
+error:
+       return (__sferror(fp) ? EOF : ret);
+       /* NOTREACHED */
+}
+
+#ifdef FLOATING_POINT
+
+#ifdef _NO_LONGDBL
+extern char *_dtoa_r _PARAMS((struct _reent *, double, int,
+                             int, int *, int *, char **));
+#else
+extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int,
+                             int, int *, int *, char **));
+#undef word0
+#define word0(x) ldword0(x)
+#endif
+
+static char *
+cvt(data, value, ndigits, flags, sign, decpt, ch, length)
+       struct _reent *data;
+#ifdef _NO_LONGDBL
+       double value;
+#else
+       _LONG_DOUBLE value;
+#endif
+       int ndigits, flags, *decpt, ch, *length;
+       char *sign;
+{
+       int mode, dsgn;
+       char *digits, *bp, *rve;
+#ifdef _NO_LONGDBL
+        union double_union tmp;
+#else
+        struct ldieee *ldptr;
+#endif
+
+       if (ch == 'f') {
+               mode = 3;               /* ndigits after the decimal point */
+       } else {
+               /* To obtain ndigits after the decimal point for the 'e' 
+                * and 'E' formats, round to ndigits + 1 significant 
+                * figures.
+                */
+               if (ch == 'e' || ch == 'E') {
+                       ndigits++;
+               }
+               mode = 2;               /* ndigits significant digits */
+       }
+
+#ifdef _NO_LONGDBL
+        tmp.d = value;
+
+       if (word0(tmp) & Sign_bit) { /* this will check for < 0 and -0.0 */
+               value = -value;
+               *sign = '-';
+        } else
+               *sign = '\000';
+
+       digits = _dtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve);
+#else /* !_NO_LONGDBL */
+       ldptr = (struct ldieee *)&value;
+       if (ldptr->sign) { /* this will check for < 0 and -0.0 */
+               value = -value;
+               *sign = '-';
+        } else
+               *sign = '\000';
+
+       digits = _ldtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve);
+#endif /* !_NO_LONGDBL */
+
+       if ((ch != 'g' && ch != 'G') || flags & ALT) {  /* Print trailing zeros */
+               bp = digits + ndigits;
+               if (ch == 'f') {
+                       if (*digits == '0' && value)
+                               *decpt = -ndigits + 1;
+                       bp += *decpt;
+               }
+               if (value == 0) /* kludge for __dtoa irregularity */
+                       rve = bp;
+               while (rve < bp)
+                       *rve++ = '0';
+       }
+       *length = rve - digits;
+       return (digits);
+}
+
+static int
+exponent(p0, exp, fmtch)
+       char *p0;
+       int exp, fmtch;
+{
+       register char *p, *t;
+       char expbuf[40];
+
+       p = p0;
+       *p++ = fmtch;
+       if (exp < 0) {
+               exp = -exp;
+               *p++ = '-';
+       }
+       else
+               *p++ = '+';
+       t = expbuf + 40;
+       if (exp > 9) {
+               do {
+                       *--t = to_char(exp % 10);
+               } while ((exp /= 10) > 9);
+               *--t = to_char(exp);
+               for (; t < expbuf + 40; *p++ = *t++);
+       }
+       else {
+               *p++ = '0';
+               *p++ = to_char(exp);
+       }
+       return (p - p0);
+}
+#endif /* FLOATING_POINT */
+
diff --git a/newlib/libc/machine/powerpc/vfscanf.c b/newlib/libc/machine/powerpc/vfscanf.c
new file mode 100644 (file)
index 0000000..b2ea572
--- /dev/null
@@ -0,0 +1,1276 @@
+/*
+FUNCTION
+<<vscanf>>, <<vfscanf>>, <<vsscanf>>---format argument list
+
+INDEX
+       vscanf
+INDEX
+       vfscanf
+INDEX
+       vsscanf
+
+ANSI_SYNOPSIS
+       #include <stdio.h>
+       #include <stdarg.h>
+       int vscanf(const char *<[fmt]>, va_list <[list]>);
+       int vfscanf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>);
+       int vsscanf(const char *<[str]>, const char *<[fmt]>, va_list <[list]>);
+
+       int _vscanf_r(void *<[reent]>, const char *<[fmt]>, 
+                       va_list <[list]>);
+       int _vfscanf_r(void *<[reent]>, FILE *<[fp]>, const char *<[fmt]>, 
+                       va_list <[list]>);
+       int _vsscanf_r(void *<[reent]>, const char *<[str]>, const char *<[fmt]>, 
+                       va_list <[list]>);
+
+TRAD_SYNOPSIS
+       #include <stdio.h>
+       #include <varargs.h>
+       int vscanf( <[fmt]>, <[ist]>)
+       char *<[fmt]>;
+       va_list <[list]>;
+
+       int vfscanf( <[fp]>, <[fmt]>, <[list]>)
+       FILE *<[fp]>;
+       char *<[fmt]>;
+       va_list <[list]>;
+       
+       int vsscanf( <[str]>, <[fmt]>, <[list]>)
+       char *<[str]>;
+       char *<[fmt]>;
+       va_list <[list]>;
+
+       int _vscanf_r( <[reent]>, <[fmt]>, <[ist]>)
+       char *<[reent]>;
+       char *<[fmt]>;
+       va_list <[list]>;
+
+       int _vfscanf_r( <[reent]>, <[fp]>, <[fmt]>, <[list]>)
+       char *<[reent]>;
+       FILE *<[fp]>;
+       char *<[fmt]>;
+       va_list <[list]>;
+       
+       int _vsscanf_r( <[reent]>, <[str]>, <[fmt]>, <[list]>)
+       char *<[reent]>;
+       char *<[str]>;
+       char *<[fmt]>;
+       va_list <[list]>;
+
+DESCRIPTION
+<<vscanf>>, <<vfscanf>>, and <<vsscanf>> are (respectively) variants
+of <<scanf>>, <<fscanf>>, and <<sscanf>>.  They differ only in 
+allowing their caller to pass the variable argument list as a 
+<<va_list>> object (initialized by <<va_start>>) rather than 
+directly accepting a variable number of arguments.
+
+RETURNS
+The return values are consistent with the corresponding functions:
+<<vscanf>> returns the number of input fields successfully scanned,
+converted, and stored; the return value does not include scanned
+fields which were not stored.  
+
+If <<vscanf>> attempts to read at end-of-file, the return value 
+is <<EOF>>.
+
+If no fields were stored, the return value is <<0>>.
+
+The routines <<_vscanf_r>>, <<_vfscanf_f>>, and <<_vsscanf_r>> are
+reentrant versions which take an additional first parameter which points to the
+reentrancy structure.
+
+PORTABILITY
+These are GNU extensions.
+
+Supporting OS subroutines required:
+*/
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <_ansi.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#ifdef _HAVE_STDC
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "local.h"
+
+#ifndef        NO_FLOATING_POINT
+#define FLOATING_POINT
+#endif
+
+#ifdef FLOATING_POINT
+#include <float.h>
+
+/* Currently a test is made to see if long double processing is warranted.
+   This could be changed in the future should the _ldtoa_r code be
+   preferred over _dtoa_r.  */
+#define _NO_LONGDBL
+#if defined WANT_IO_LONG_DBL && (LDBL_MANT_DIG > DBL_MANT_DIG)
+#undef _NO_LONGDBL
+extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr));
+#endif
+
+#define _NO_LONGLONG
+#if defined WANT_PRINTF_LONG_LONG && defined __GNUC__
+# undef _NO_LONGLONG
+#endif
+
+#include "floatio.h"
+#define        BUF     (MAXEXP+MAXFRACT+3)     /* 3 = sign + decimal point + NUL */
+/* An upper bound for how long a long prints in decimal.  4 / 13 approximates
+   log (2).  Add one char for roundoff compensation and one for the sign.  */
+#define MAX_LONG_LEN ((CHAR_BIT * sizeof (long)  - 1) * 4 / 13 + 2)
+#else
+#define        BUF     40
+#endif
+
+/*
+ * Flags used during conversion.
+ */
+
+#define        LONG            0x01    /* l: long or double */
+#define        LONGDBL         0x02    /* L: long double or long long */
+#define        SHORT           0x04    /* h: short */
+#define        SUPPRESS        0x08    /* suppress assignment */
+#define        POINTER         0x10    /* weird %p pointer (`fake hex') */
+#define        NOSKIP          0x20    /* do not skip blanks */
+
+/*
+ * The following are used in numeric conversions only:
+ * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
+ * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
+ */
+
+#define        SIGNOK          0x40    /* +/- is (still) legal */
+#define        NDIGITS         0x80    /* no digits detected */
+
+#define        DPTOK           0x100   /* (float) decimal point is still legal */
+#define        EXPOK           0x200   /* (float) exponent (e+3, etc) still legal */
+
+#define        PFXOK           0x100   /* 0x prefix is (still) legal */
+#define        NZDIGITS        0x200   /* no zero digits detected */
+
+#define        VECTOR          0x400   /* v: vector */
+
+/*
+ * Conversion types.
+ */
+
+#define        CT_CHAR         0       /* %c conversion */
+#define        CT_CCL          1       /* %[...] conversion */
+#define        CT_STRING       2       /* %s conversion */
+#define        CT_INT          3       /* integer, i.e., strtol or strtoul */
+#define        CT_FLOAT        4       /* floating, i.e., strtod */
+
+#if 0
+#define u_char unsigned char
+#endif
+#define u_char char
+#define u_long unsigned long
+
+#ifndef _NO_LONGLONG
+typedef unsigned long long u_long_long;
+#endif
+
+typedef union
+{
+  char c[16] __attribute__ ((__aligned__ (16)));
+  short h[8];
+  long l[4];
+  int i[4];
+  float f[4];
+} vec_union;
+
+/*static*/ u_char *__sccl ();
+
+/*
+ * vfscanf
+ */
+
+#define BufferEmpty (fp->_r <= 0 && __srefill(fp))
+
+#ifndef _REENT_ONLY
+
+int
+_DEFUN (vfscanf, (fp, fmt, ap), 
+    register FILE *fp _AND 
+    _CONST char *fmt _AND 
+    va_list ap)
+{
+  CHECK_INIT(fp);
+  return __svfscanf_r (fp->_data, fp, fmt, ap);
+}
+
+int
+__svfscanf (fp, fmt0, ap)
+     register FILE *fp;
+     char _CONST *fmt0;
+     va_list ap;
+{
+  return __svfscanf_r (_REENT, fp, fmt0, ap);
+}
+
+#endif /* !_REENT_ONLY */
+
+int
+_DEFUN (_vfscanf_r, (data, fp, fmt, ap),
+    struct _reent *data _AND 
+    register FILE *fp _AND 
+    _CONST char *fmt _AND 
+    va_list ap)
+{
+  return __svfscanf_r (data, fp, fmt, ap);
+}
+
+
+int
+__svfscanf_r (rptr, fp, fmt0, ap)
+     struct _reent *rptr;
+     register FILE *fp;
+     char _CONST *fmt0;
+     va_list ap;
+{
+  register u_char *fmt = (u_char *) fmt0;
+  register int c;              /* character from format, or conversion */
+  register int type;           /* conversion type */
+  register size_t width;       /* field width, or 0 */
+  register char *p;            /* points into all kinds of strings */
+  register int n;              /* handy integer */
+  register int flags;          /* flags as defined above */
+  register char *p0;           /* saves original value of p when necessary */
+  int orig_flags;               /* saved flags used when processing vector */
+  int int_width;                /* tmp area to store width when processing int */
+  int nassigned;               /* number of fields assigned */
+  int nread;                   /* number of characters consumed from fp */
+  int base = 0;                        /* base argument to strtol/strtoul */
+  int nbytes = 1;               /* number of bytes read from fmt string */
+  wchar_t wc;                   /* wchar to use to read format string */
+  char vec_sep;                 /* vector separator char */
+  char last_space_char;         /* last white-space char eaten - needed for vec support */
+  int vec_read_count;           /* number of vector items to read separately */
+  int looped;                   /* has vector processing looped */
+  u_long (*ccfn) () = 0;       /* conversion function (strtol/strtoul) */
+  char ccltab[256];            /* character class table for %[...] */
+  char buf[BUF];               /* buffer for numeric conversions */
+  vec_union vec_buf;
+  char *lptr;                   /* literal pointer */
+#ifdef MB_CAPABLE
+  int state = 0;                /* value to keep track of multibyte state */
+#endif
+
+  char *ch_dest;
+  short *sp;
+  int *ip;
+  float *flp;
+  _LONG_DOUBLE *ldp;
+  double *dp;
+  long *lp;
+#ifndef _NO_LONGLONG
+  long long *llp;
+#else
+       u_long _uquad;
+#endif
+
+  /* `basefix' is used to avoid `if' tests in the integer scanner */
+  static _CONST short basefix[17] =
+    {10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+
+  nassigned = 0;
+  nread = 0;
+  for (;;)
+    {
+#ifndef MB_CAPABLE
+      wc = *fmt;
+#else
+      nbytes = _mbtowc_r (rptr, &wc, fmt, MB_CUR_MAX, &state);
+#endif
+      fmt += nbytes;
+      if (wc == 0)
+       return nassigned;
+      if (nbytes == 1 && isspace (wc))
+       {
+         for (;;)
+           {
+             if (BufferEmpty)
+               return nassigned;
+             if (!isspace (*fp->_p))
+               break;
+             nread++, fp->_r--, fp->_p++;
+           }
+         continue;
+       }
+      if (wc != '%')
+       goto literal;
+      width = 0;
+      flags = 0;
+      vec_sep = ' ';
+      vec_read_count = 0;
+      looped = 0;
+
+      /*
+       * switch on the format.  continue if done; break once format
+       * type is derived.
+       */
+
+    again:
+      c = *fmt++;
+
+      switch (c)
+       {
+       case '%':
+       literal:
+          lptr = fmt - nbytes;
+          for (n = 0; n < nbytes; ++n)
+            {
+             if (BufferEmpty)
+               goto input_failure;
+             if (*fp->_p != *lptr)
+               goto match_failure;
+             fp->_r--, fp->_p++;
+             nread++;
+              ++lptr;
+            }
+         continue;
+
+       case '*':
+         flags |= SUPPRESS;
+         goto again;
+       case ',':
+       case ';':
+       case ':':
+       case '_':
+         if (flags == SUPPRESS || flags == 0)
+           vec_sep = c;
+         goto again;
+       case 'l':
+         if (flags & LONG)
+           {
+             flags &= ~LONG;
+             flags &= ~VECTOR;
+             flags |= LONGDBL;
+           }
+         else
+           flags |= LONG;
+         goto again;
+       case 'L':
+         flags |= LONGDBL;
+         flags &= ~VECTOR;
+         goto again;
+       case 'h':
+         flags |= SHORT;
+         if (flags & VECTOR)
+           vec_read_count = 8;
+         goto again;
+#ifdef __ALTIVEC__
+       case 'v':
+         flags |= VECTOR;
+         vec_read_count = (flags & SHORT) ? 8 : 4;
+         goto again;
+#endif
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         width = width * 10 + c - '0';
+         goto again;
+
+         /*
+          * Conversions. Those marked `compat' are for
+          * 4.[123]BSD compatibility.
+          *
+          * (According to ANSI, E and X formats are supposed to
+          * the same as e and x.  Sorry about that.)
+          */
+
+       case 'D':               /* compat */
+         flags |= LONG;
+         /* FALLTHROUGH */
+       case 'd':
+         type = CT_INT;
+         ccfn = (u_long (*)())_strtol_r;
+         base = 10;
+         break;
+
+       case 'i':
+         type = CT_INT;
+         ccfn = (u_long (*)())_strtol_r;
+         base = 0;
+         break;
+
+       case 'O':               /* compat */
+         flags |= LONG;
+         /* FALLTHROUGH */
+       case 'o':
+         type = CT_INT;
+         ccfn = _strtoul_r;
+         base = 8;
+         break;
+
+       case 'u':
+         type = CT_INT;
+         ccfn = _strtoul_r;
+         base = 10;
+         break;
+
+       case 'X':               /* compat   XXX */
+       case 'x':
+         flags |= PFXOK;       /* enable 0x prefixing */
+         type = CT_INT;
+         ccfn = _strtoul_r;
+         base = 16;
+         break;
+
+#ifdef FLOATING_POINT
+       case 'E':               /* compat   XXX */
+       case 'G':               /* compat   XXX */
+/* ANSI says that E,G and X behave the same way as e,g,x */
+         /* FALLTHROUGH */
+       case 'e':
+       case 'f':
+       case 'g':
+         type = CT_FLOAT;
+         if (flags & VECTOR)
+           vec_read_count = 4;
+         break;
+       
+#endif
+
+       case 's':
+         flags &= ~VECTOR;
+         type = CT_STRING;
+         break;
+
+       case '[':
+         fmt = __sccl (ccltab, fmt);
+         flags |= NOSKIP;
+         flags &= ~VECTOR;
+         type = CT_CCL;
+         break;
+
+       case 'c':
+         flags |= NOSKIP;
+         type = CT_CHAR;
+         if (flags & VECTOR)
+           {
+             width = 0;
+             vec_read_count = 16;
+           }
+         break;
+
+       case 'p':               /* pointer format is like hex */
+         flags |= POINTER | PFXOK;
+         flags &= ~VECTOR;
+         type = CT_INT;
+         ccfn = _strtoul_r;
+         base = 16;
+         break;
+
+       case 'n':
+         if (flags & SUPPRESS) /* ??? */
+           continue;
+         flags &= ~VECTOR;
+         if (flags & SHORT)
+           {
+             sp = va_arg (ap, short *);
+             *sp = nread;
+           }
+         else if (flags & LONG)
+           {
+             lp = va_arg (ap, long *);
+             *lp = nread;
+           }
+#ifndef _NO_LONGLONG
+         else if (flags & LONGDBL)
+           {
+             llp = va_arg (ap, long long*);
+             *llp = nread;
+           }
+#endif
+         else
+           {
+             ip = va_arg (ap, int *);
+             *ip = nread;
+           }
+         continue;
+
+         /*
+          * Disgusting backwards compatibility hacks.  XXX
+          */
+       case '\0':              /* compat */
+         return EOF;
+
+       default:                /* compat */
+         if (isupper (c))
+           flags |= LONG;
+         type = CT_INT;
+         ccfn = (u_long (*)())_strtol_r;
+         base = 10;
+         break;
+       }
+
+    process:
+      /*
+       * We have a conversion that requires input.
+       */
+      if (BufferEmpty)
+       goto input_failure;
+
+      /*
+       * Consume leading white space, except for formats that
+       * suppress this.
+       */
+      last_space_char = '\0';
+
+      if ((flags & NOSKIP) == 0)
+       {
+         while (isspace (*fp->_p))
+           {
+             last_space_char = *fp->_p;
+             nread++;
+             if (--fp->_r > 0)
+               fp->_p++;
+             else
+#ifndef CYGNUS_NEC
+             if (__srefill (fp))
+#endif
+               goto input_failure;
+           }
+         /*
+          * Note that there is at least one character in the
+          * buffer, so conversions that do not set NOSKIP ca
+          * no longer result in an input failure.
+          */
+       }
+
+      /* for vector formats process separator characters after first loop */
+      if (looped && (flags & VECTOR))
+       {
+         flags = orig_flags; 
+         /* all formats other than default char have a separator char */
+         if (vec_sep != ' ' || type != CT_CHAR)
+           {
+             if (vec_sep == ' ' && last_space_char != ' ' ||
+                 vec_sep != ' ' && *fp->_p != vec_sep)
+               goto input_failure;
+             if (vec_sep != ' ')
+               {
+                 nread++;
+                 if (--fp->_r > 0)
+                   fp->_p++;
+                 else
+#ifndef CYGNUS_NEC
+                   if (__srefill (fp))
+#endif
+                     goto input_failure;
+               }
+           }
+         /* after eating the separator char, we must eat any white-space
+            after the separator char that precedes the data to convert */
+         if ((flags & NOSKIP) == 0)
+           {
+             while (isspace (*fp->_p))
+               {
+                 last_space_char = *fp->_p;
+                 nread++;
+                 if (--fp->_r > 0)
+                   fp->_p++;
+                 else
+#ifndef CYGNUS_NEC
+                   if (__srefill (fp))
+#endif
+                     goto input_failure;
+               }
+           }
+
+       }
+      else /* save to counter-act changes made to flags when processing */
+       orig_flags = flags;
+
+      /*
+       * Do the conversion.
+       */
+      switch (type)
+       {
+
+       case CT_CHAR:
+         /* scan arbitrary characters (sets NOSKIP) */
+         if (width == 0)
+           width = 1;
+         if (flags & SUPPRESS)
+           {
+             size_t sum = 0;
+
+             for (;;)
+               {
+                 if ((n = fp->_r) < (int)width)
+                   {
+                     sum += n;
+                     width -= n;
+                     fp->_p += n;
+#ifndef CYGNUS_NEC
+                     if (__srefill (fp))
+                       {
+#endif
+                         if (sum == 0)
+                           goto input_failure;
+                         break;
+#ifndef CYGNUS_NEC
+                       }
+#endif
+                   }
+                 else
+                   {
+                     sum += width;
+                     fp->_r -= width;
+                     fp->_p += width;
+                     break;
+                   }
+               }
+             nread += sum;
+           }
+         else
+           {
+             int n = width;
+             if (!looped)
+               {
+                 if (flags & VECTOR)
+                   ch_dest = vec_buf.c;
+                 else
+                   ch_dest = va_arg (ap, char *);
+               }
+#ifdef CYGNUS_NEC
+             /* Kludge city for the moment */
+             if (fp->_r == 0)
+               goto input_failure;
+
+             while (n && fp->_r)
+               {
+                 *ch_dest++ = *(fp->_p++);
+                 n--;
+                 fp->_r--;
+                 nread++;
+               }
+#else
+             size_t r = fread (ch_dest, 1, width, fp);
+
+             if (r == 0)
+               goto input_failure;
+             nread += r;
+             ch_dest += r;
+#endif
+             if (!(flags & VECTOR))
+               nassigned++;
+           }
+         break;
+
+       case CT_CCL:
+         /* scan a (nonempty) character class (sets NOSKIP) */
+         if (width == 0)
+           width = ~0;         /* `infinity' */
+         /* take only those things in the class */
+         if (flags & SUPPRESS)
+           {
+             n = 0;
+             while (ccltab[*fp->_p])
+               {
+                 n++, fp->_r--, fp->_p++;
+                 if (--width == 0)
+                   break;
+                 if (BufferEmpty)
+                   {
+                     if (n == 0)
+                       goto input_failure;
+                     break;
+                   }
+               }
+             if (n == 0)
+               goto match_failure;
+           }
+         else
+           {
+             p0 = p = va_arg (ap, char *);
+             while (ccltab[*fp->_p])
+               {
+                 fp->_r--;
+                 *p++ = *fp->_p++;
+                 if (--width == 0)
+                   break;
+                 if (BufferEmpty)
+                   {
+                     if (p == p0)
+                       goto input_failure;
+                     break;
+                   }
+               }
+             n = p - p0;
+             if (n == 0)
+               goto match_failure;
+             *p = 0;
+             nassigned++;
+           }
+         nread += n;
+         break;
+
+       case CT_STRING:
+         /* like CCL, but zero-length string OK, & no NOSKIP */
+         if (width == 0)
+           width = ~0;
+         if (flags & SUPPRESS)
+           {
+             n = 0;
+             while (!isspace (*fp->_p))
+               {
+                 n++, fp->_r--, fp->_p++;
+                 if (--width == 0)
+                   break;
+                 if (BufferEmpty)
+                   break;
+               }
+             nread += n;
+           }
+         else
+           {
+             p0 = p = va_arg (ap, char *);
+             while (!isspace (*fp->_p))
+               {
+                 fp->_r--;
+                 *p++ = *fp->_p++;
+                 if (--width == 0)
+                   break;
+                 if (BufferEmpty)
+                   break;
+               }
+             *p = 0;
+             nread += p - p0;
+             nassigned++;
+           }
+         continue;
+
+       case CT_INT:
+         /* scan an integer as if by strtol/strtoul */
+         int_width = width;
+#ifdef hardway
+         if (int_width == 0 || int_width > sizeof (buf) - 1)
+           int_width = sizeof (buf) - 1;
+#else
+         /* size_t is unsigned, hence this optimisation */
+         if (--int_width > sizeof (buf) - 2)
+           int_width = sizeof (buf) - 2;
+         int_width++;
+#endif
+         flags |= SIGNOK | NDIGITS | NZDIGITS;
+         for (p = buf; int_width; int_width--)
+           {
+             c = *fp->_p;
+             /*
+              * Switch on the character; `goto ok' if we
+              * accept it as a part of number.
+              */
+             switch (c)
+               {
+                 /*
+                  * The digit 0 is always legal, but is special.
+                  * For %i conversions, if no digits (zero or nonzero)
+                  * have been scanned (only signs), we will have base==0.
+                  * In that case, we should set it to 8 and enable 0x
+                  * prefixing. Also, if we have not scanned zero digits
+                  * before this, do not turn off prefixing (someone else
+                  * will turn it off if we have scanned any nonzero digits).
+                  */
+               case '0':
+                 if (base == 0)
+                   {
+                     base = 8;
+                     flags |= PFXOK;
+                   }
+                 if (flags & NZDIGITS)
+                   flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
+                 else
+                   flags &= ~(SIGNOK | PFXOK | NDIGITS);
+                 goto ok;
+
+                 /* 1 through 7 always legal */
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+                 base = basefix[base];
+                 flags &= ~(SIGNOK | PFXOK | NDIGITS);
+                 goto ok;
+
+                 /* digits 8 and 9 ok iff decimal or hex */
+               case '8':
+               case '9':
+                 base = basefix[base];
+                 if (base <= 8)
+                   break;      /* not legal here */
+                 flags &= ~(SIGNOK | PFXOK | NDIGITS);
+                 goto ok;
+
+                 /* letters ok iff hex */
+               case 'A':
+               case 'B':
+               case 'C':
+               case 'D':
+               case 'E':
+               case 'F':
+               case 'a':
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'e':
+               case 'f':
+                 /* no need to fix base here */
+                 if (base <= 10)
+                   break;      /* not legal here */
+                 flags &= ~(SIGNOK | PFXOK | NDIGITS);
+                 goto ok;
+
+                 /* sign ok only as first character */
+               case '+':
+               case '-':
+                 if (flags & SIGNOK)
+                   {
+                     flags &= ~SIGNOK;
+                     goto ok;
+                   }
+                 break;
+
+                 /* x ok iff flag still set & 2nd char */
+               case 'x':
+               case 'X':
+                 if (flags & PFXOK && p == buf + 1)
+                   {
+                     base = 16;/* if %i */
+                     flags &= ~PFXOK;
+                     goto ok;
+                   }
+                 break;
+               }
+
+             /*
+              * If we got here, c is not a legal character
+              * for a number.  Stop accumulating digits.
+              */
+             break;
+           ok:
+             /*
+              * c is legal: store it and look at the next.
+              */
+             *p++ = c;
+             if (--fp->_r > 0)
+               fp->_p++;
+             else
+#ifndef CYGNUS_NEC
+             if (__srefill (fp))
+#endif
+               break;          /* EOF */
+           }
+         /*
+          * If we had only a sign, it is no good; push back the sign.
+          * If the number ends in `x', it was [sign] '0' 'x', so push back
+          * the x and treat it as [sign] '0'.
+          */
+         if (flags & NDIGITS)
+           {
+             if (p > buf)
+               _CAST_VOID ungetc (*(u_char *)-- p, fp);
+             goto match_failure;
+           }
+         c = ((u_char *) p)[-1];
+         if (c == 'x' || c == 'X')
+           {
+             --p;
+             /*(void)*/ ungetc (c, fp);
+           }
+         if ((flags & SUPPRESS) == 0)
+           {
+             u_long res;
+
+             *p = 0;
+             res = (*ccfn) (rptr, buf, (char **) NULL, base);
+             if (flags & POINTER)
+               *(va_arg (ap, _PTR *)) = (_PTR) (unsigned _POINTER_INT) res;
+             else if (flags & SHORT)
+               {
+                 if (!(flags & VECTOR))
+                   sp = va_arg (ap, short *);
+                 else if (!looped)
+                   sp = vec_buf.h;
+                 *sp++ = res;
+               }
+             else if (flags & LONG)
+               {
+                 if (!(flags & VECTOR))
+                   lp = va_arg (ap, long *);
+                 else if (!looped)
+                   lp = vec_buf.l;
+                 *lp++ = res;
+               }
+#ifndef _NO_LONGLONG
+             else if (flags & LONGDBL)
+               {
+                 u_long_long resll;
+                 if (ccfn == _strtoul_r)
+                   resll = _strtoull_r (rptr, buf, (char **) NULL, base);
+                 else
+                   resll = _strtoll_r (rptr, buf, (char **) NULL, base);
+                 llp = va_arg (ap, long long*);
+                 *llp = resll;
+               }
+#endif
+             else
+               {
+                 if (!(flags & VECTOR))
+                   ip = va_arg (ap, int *);
+                 else if (!looped)
+                   ip = vec_buf.i;
+                 *ip++ = res;
+               }
+             if (!(flags & VECTOR))
+               nassigned++;
+           }
+         nread += p - buf;
+         break;
+
+#ifdef FLOATING_POINT
+       case CT_FLOAT:
+       {
+         /* scan a floating point number as if by strtod */
+         /* This code used to assume that the number of digits is reasonable.
+            However, ANSI / ISO C makes no such stipulation; we have to get
+            exact results even when there is an unreasonable amount of
+            leading zeroes.  */
+         long leading_zeroes = 0;
+         long zeroes, exp_adjust;
+         char *exp_start = NULL;
+         int fl_width = width;
+#ifdef hardway
+         if (fl_width == 0 || fl_width > sizeof (buf) - 1)
+           fl_width = sizeof (buf) - 1;
+#else
+         /* size_t is unsigned, hence this optimisation */
+         if (--fl_width > sizeof (buf) - 2)
+           fl_width = sizeof (buf) - 2;
+         fl_width++;
+#endif
+         flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
+         zeroes = 0;
+         exp_adjust = 0;
+         for (p = buf; fl_width; )
+           {
+             c = *fp->_p;
+             /*
+              * This code mimicks the integer conversion
+              * code, but is much simpler.
+              */
+             switch (c)
+               {
+
+               case '0':
+                 if (flags & NDIGITS)
+                   {
+                     flags &= ~SIGNOK;
+                     zeroes++;
+                     goto fskip;
+                   }
+                 /* Fall through.  */
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+                 flags &= ~(SIGNOK | NDIGITS);
+                 goto fok;
+
+               case '+':
+               case '-':
+                 if (flags & SIGNOK)
+                   {
+                     flags &= ~SIGNOK;
+                     goto fok;
+                   }
+                 break;
+               case '.':
+                 if (flags & DPTOK)
+                   {
+                     flags &= ~(SIGNOK | DPTOK);
+                     leading_zeroes = zeroes;
+                     goto fok;
+                   }
+                 break;
+               case 'e':
+               case 'E':
+                 /* no exponent without some digits */
+                 if ((flags & (NDIGITS | EXPOK)) == EXPOK
+                     || ((flags & EXPOK) && zeroes))
+                   {
+                     if (! (flags & DPTOK))
+                       {
+                         exp_adjust = zeroes - leading_zeroes;
+                         exp_start = p;
+                       }
+                     flags =
+                       (flags & ~(EXPOK | DPTOK)) |
+                       SIGNOK | NDIGITS;
+                     zeroes = 0;
+                     goto fok;
+                   }
+                 break;
+               }
+             break;
+           fok:
+             *p++ = c;
+             fl_width--;
+           fskip:
+              ++nread;
+             if (--fp->_r > 0)
+               fp->_p++;
+             else
+#ifndef CYGNUS_NEC
+             if (__srefill (fp))
+#endif
+               break;          /* EOF */
+           }
+         if (zeroes)
+           flags &= ~NDIGITS;
+         /*
+          * If no digits, might be missing exponent digits
+          * (just give back the exponent) or might be missing
+          * regular digits, but had sign and/or decimal point.
+          */
+         if (flags & NDIGITS)
+           {
+             if (flags & EXPOK)
+               {
+                 /* no digits at all */
+                 while (p > buf)
+                    {
+                     ungetc (*(u_char *)-- p, fp);
+                      --nread;
+                    }
+                 goto match_failure;
+               }
+             /* just a bad exponent (e and maybe sign) */
+             c = *(u_char *)-- p;
+              --nread;
+             if (c != 'e' && c != 'E')
+               {
+                 _CAST_VOID ungetc (c, fp);    /* sign */
+                 c = *(u_char *)-- p;
+                  --nread;
+               }
+             _CAST_VOID ungetc (c, fp);
+           }
+         if ((flags & SUPPRESS) == 0)
+           {
+#ifdef _NO_LONGDBL
+             double res;
+#else  /* !_NO_LONG_DBL */
+             long double res;
+#endif /* !_NO_LONG_DBL */
+             long new_exp = 0;
+
+             *p = 0;
+             if ((flags & (DPTOK | EXPOK)) == EXPOK)
+               {
+                 exp_adjust = zeroes - leading_zeroes;
+                 new_exp = -exp_adjust;
+                 exp_start = p;
+               }
+             else if (exp_adjust)
+                new_exp = _strtol_r (rptr, (exp_start + 1), NULL, 10) - exp_adjust;
+             if (exp_adjust)
+               {
+
+                 /* If there might not be enough space for the new exponent,
+                    truncate some trailing digits to make room.  */
+                 if (exp_start >= buf + sizeof (buf) - MAX_LONG_LEN)
+                   exp_start = buf + sizeof (buf) - MAX_LONG_LEN - 1;
+                 sprintf (exp_start, "e%ld", new_exp);
+               }
+#ifdef _NO_LONGDBL
+             res = _strtod_r (rptr, buf, NULL);
+#else  /* !_NO_LONGDBL */
+             res = _strtold (buf, NULL);
+#endif /* !_NO_LONGDBL */
+             if (flags & LONG)
+               {
+                 dp = va_arg (ap, double *);
+                 *dp = res;
+               }
+             else if (flags & LONGDBL)
+               {
+                 ldp = va_arg (ap, _LONG_DOUBLE *);
+                 *ldp = res;
+               }
+             else
+               {
+                 if (!(flags & VECTOR))
+                   flp = va_arg (ap, float *);
+                 else if (!looped)
+                   flp = vec_buf.f;
+                 *flp++ = res;
+               }
+             if (!(flags & VECTOR))
+               nassigned++;
+           }
+         break;
+       }
+#endif /* FLOATING_POINT */
+       }
+      if (vec_read_count-- > 1)
+       {
+         looped = 1;
+         goto process;
+       }
+      if (flags & VECTOR)
+       {
+         int i;
+         unsigned long *vp = va_arg (ap, unsigned long *);
+         for (i = 0; i < 4; ++i)
+           *vp++ = vec_buf.l[i];
+       }
+    }
+input_failure:
+  return nassigned ? nassigned : -1;
+match_failure:
+  return nassigned;
+}
+
+/*
+ * Fill in the given table from the scanset at the given format
+ * (just after `[').  Return a pointer to the character past the
+ * closing `]'.  The table has a 1 wherever characters should be
+ * considered part of the scanset.
+ */
+
+/*static*/
+u_char *
+__sccl (tab, fmt)
+     register char *tab;
+     register u_char *fmt;
+{
+  register int c, n, v;
+
+  /* first `clear' the whole table */
+  c = *fmt++;                  /* first char hat => negated scanset */
+  if (c == '^')
+    {
+      v = 1;                   /* default => accept */
+      c = *fmt++;              /* get new first char */
+    }
+  else
+    v = 0;                     /* default => reject */
+  /* should probably use memset here */
+  for (n = 0; n < 256; n++)
+    tab[n] = v;
+  if (c == 0)
+    return fmt - 1;            /* format ended before closing ] */
+
+  /*
+   * Now set the entries corresponding to the actual scanset to the
+   * opposite of the above.
+   *
+   * The first character may be ']' (or '-') without being special; the
+   * last character may be '-'.
+   */
+
+  v = 1 - v;
+  for (;;)
+    {
+      tab[c] = v;              /* take character c */
+    doswitch:
+      n = *fmt++;              /* and examine the next */
+      switch (n)
+       {
+
+       case 0:         /* format ended too soon */
+         return fmt - 1;
+
+       case '-':
+         /*
+          * A scanset of the form [01+-] is defined as `the digit 0, the
+          * digit 1, the character +, the character -', but the effect of a
+          * scanset such as [a-zA-Z0-9] is implementation defined.  The V7
+          * Unix scanf treats `a-z' as `the letters a through z', but treats
+          * `a-a' as `the letter a, the character -, and the letter a'.
+          *
+          * For compatibility, the `-' is not considerd to define a range if
+          * the character following it is either a close bracket (required by
+          * ANSI) or is not numerically greater than the character we just
+          * stored in the table (c).
+          */
+         n = *fmt;
+         if (n == ']' || n < c)
+           {
+             c = '-';
+             break;            /* resume the for(;;) */
+           }
+         fmt++;
+         do
+           {                   /* fill in the range */
+             tab[++c] = v;
+           }
+         while (c < n);
+#if 1                  /* XXX another disgusting compatibility hack */
+         /*
+          * Alas, the V7 Unix scanf also treats formats such
+          * as [a-c-e] as `the letters a through e'. This too
+          * is permitted by the standard....
+          */
+         goto doswitch;
+#else
+         c = *fmt++;
+         if (c == 0)
+           return fmt - 1;
+         if (c == ']')
+           return fmt;
+#endif
+
+         break;
+
+
+       case ']':               /* end of scanset */
+         return fmt;
+
+       default:                /* just another character */
+         c = n;
+         break;
+       }
+    }
+  /* NOTREACHED */
+}