Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Johnston <jjohnstn@redhat.com>2002-04-19 23:16:22 +0400
committerJeff Johnston <jjohnstn@redhat.com>2002-04-19 23:16:22 +0400
commit0d844014bfbcab4e48718b787c268d052f773197 (patch)
tree30f19160e87bedae028d33a2839bf51a7b10bac6
parentd413aadcafc1fc287fa01cb28dd04f495111e418 (diff)
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.
-rw-r--r--newlib/ChangeLog27
-rw-r--r--newlib/configure.host3
-rw-r--r--newlib/libc/include/machine/malloc.h8
-rw-r--r--newlib/libc/include/machine/setjmp.h4
-rw-r--r--newlib/libc/include/machine/stdlib.h8
-rw-r--r--newlib/libc/include/malloc.h3
-rw-r--r--newlib/libc/include/stdlib.h2
-rw-r--r--newlib/libc/machine/powerpc/Makefile.am15
-rw-r--r--newlib/libc/machine/powerpc/Makefile.in19
-rwxr-xr-xnewlib/libc/machine/powerpc/configure13
-rw-r--r--newlib/libc/machine/powerpc/configure.in11
-rw-r--r--newlib/libc/machine/powerpc/machine/malloc.h20
-rw-r--r--newlib/libc/machine/powerpc/machine/stdlib.h24
-rw-r--r--newlib/libc/machine/powerpc/setjmp.S74
-rw-r--r--newlib/libc/machine/powerpc/vec_calloc.c66
-rw-r--r--newlib/libc/machine/powerpc/vec_free.c15
-rw-r--r--newlib/libc/machine/powerpc/vec_malloc.c132
-rw-r--r--newlib/libc/machine/powerpc/vec_mallocr.c424
-rw-r--r--newlib/libc/machine/powerpc/vec_realloc.c17
-rw-r--r--newlib/libc/machine/powerpc/vfprintf.c1195
-rw-r--r--newlib/libc/machine/powerpc/vfscanf.c1276
21 files changed, 3350 insertions, 6 deletions
diff --git a/newlib/ChangeLog b/newlib/ChangeLog
index a0e370b34..45a3ec0ed 100644
--- a/newlib/ChangeLog
+++ b/newlib/ChangeLog
@@ -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
diff --git a/newlib/configure.host b/newlib/configure.host
index 264632e5f..aaab9c446 100644
--- a/newlib/configure.host
+++ b/newlib/configure.host
@@ -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
index 000000000..fdada9ed7
--- /dev/null
+++ b/newlib/libc/include/machine/malloc.h
@@ -0,0 +1,8 @@
+#ifndef _MACHMALLOC_H_
+#define _MACHMALLOC_H_
+
+/* place holder so platforms may add malloc.h extensions */
+
+#endif /* _MACHMALLOC_H_ */
+
+
diff --git a/newlib/libc/include/machine/setjmp.h b/newlib/libc/include/machine/setjmp.h
index c7f146338..e4c788b2f 100644
--- a/newlib/libc/include/machine/setjmp.h
+++ b/newlib/libc/include/machine/setjmp.h
@@ -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
index 000000000..fa3f3a139
--- /dev/null
+++ b/newlib/libc/include/machine/stdlib.h
@@ -0,0 +1,8 @@
+#ifndef _MACHSTDLIB_H_
+#define _MACHSTDLIB_H_
+
+/* place holder so platforms may add stdlib.h extensions */
+
+#endif /* _MACHSTDLIB_H_ */
+
+
diff --git a/newlib/libc/include/malloc.h b/newlib/libc/include/malloc.h
index 5ccdda61c..08a14252a 100644
--- a/newlib/libc/include/malloc.h
+++ b/newlib/libc/include/malloc.h
@@ -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
diff --git a/newlib/libc/include/stdlib.h b/newlib/libc/include/stdlib.h
index 00a9d1ab3..eb8f54d1e 100644
--- a/newlib/libc/include/stdlib.h
+++ b/newlib/libc/include/stdlib.h
@@ -17,7 +17,7 @@ extern "C" {
#include <stddef.h>
#include <sys/reent.h>
-
+#include <machine/stdlib.h>
#ifndef __STRICT_ANSI__
#include <alloca.h>
#endif
diff --git a/newlib/libc/machine/powerpc/Makefile.am b/newlib/libc/machine/powerpc/Makefile.am
index 1c65b9ffe..4ddc19ac8 100644
--- a/newlib/libc/machine/powerpc/Makefile.am
+++ b/newlib/libc/machine/powerpc/Makefile.am
@@ -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 $@
+
diff --git a/newlib/libc/machine/powerpc/Makefile.in b/newlib/libc/machine/powerpc/Makefile.in
index ace6f0612..d2721cb8a 100644
--- a/newlib/libc/machine/powerpc/Makefile.in
+++ b/newlib/libc/machine/powerpc/Makefile.in
@@ -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:
diff --git a/newlib/libc/machine/powerpc/configure b/newlib/libc/machine/powerpc/configure
index e55c23286..15a7a2b84 100755
--- a/newlib/libc/machine/powerpc/configure
+++ b/newlib/libc/machine/powerpc/configure
@@ -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
diff --git a/newlib/libc/machine/powerpc/configure.in b/newlib/libc/machine/powerpc/configure.in
index 47b9eab78..655c08667 100644
--- a/newlib/libc/machine/powerpc/configure.in
+++ b/newlib/libc/machine/powerpc/configure.in
@@ -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
index 000000000..945a9651a
--- /dev/null
+++ b/newlib/libc/machine/powerpc/machine/malloc.h
@@ -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
index 000000000..17e9dc32d
--- /dev/null
+++ b/newlib/libc/machine/powerpc/machine/stdlib.h
@@ -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_ */
+
+
diff --git a/newlib/libc/machine/powerpc/setjmp.S b/newlib/libc/machine/powerpc/setjmp.S
index c1376912f..ec3a443d7 100644
--- a/newlib/libc/machine/powerpc/setjmp.S
+++ b/newlib/libc/machine/powerpc/setjmp.S
@@ -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
index 000000000..5efe91049
--- /dev/null
+++ b/newlib/libc/machine/powerpc/vec_calloc.c
@@ -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
index 000000000..b55c52dde
--- /dev/null
+++ b/newlib/libc/machine/powerpc/vec_free.c
@@ -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
index 000000000..6bcad59b6
--- /dev/null
+++ b/newlib/libc/machine/powerpc/vec_malloc.c
@@ -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
index 000000000..c375c8be2
--- /dev/null
+++ b/newlib/libc/machine/powerpc/vec_mallocr.c
@@ -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)))
+
+
+
+
+/*
+ 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))
+
+
+
+#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 */
+
+
+#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
index 000000000..e192e399d
--- /dev/null
+++ b/newlib/libc/machine/powerpc/vec_realloc.c
@@ -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
index 000000000..cf054293b
--- /dev/null
+++ b/newlib/libc/machine/powerpc/vfprintf.c
@@ -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
index 000000000..b2ea57274
--- /dev/null
+++ b/newlib/libc/machine/powerpc/vfscanf.c
@@ -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 */
+}