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 + + * configure.host: Add support for powerpc-eabialtivec*. + * libc/include/malloc.h: Add include of . + * libc/include/stdlib.h: Add include of . + * 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 * 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 +/* include any machine-specific extensions */ +#include + #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 #include - +#include #ifndef __STRICT_ANSI__ #include #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 +<>---allocate space for arrays + +INDEX + vec_calloc + +INDEX + _vec_calloc_r + +ANSI_SYNOPSIS + #include + void *vec_calloc(size_t <[n]>, size_t <[s]>); + void *vec_calloc_r(void *<[reent]>, size_t , <[s]>); + +TRAD_SYNOPSIS + #include + 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 <> to request a block of memory sufficient to hold an +array of <[n]> elements, each of which has size <[s]>. + +The memory allocated by <> comes out of the same memory pool +used by <>, but the memory block is initialized to all zero +bytes. (To avoid the overhead of initializing the space, use +<> 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, <>. + +PORTABILITY +<> is an non-ANSI extension described in the AltiVec Programming +Interface Manual. + +Supporting OS subroutines required: <>, <>, <>, +<>, <>, <>, <>. +*/ + +#include +#include + +#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 +#include + +#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 +<>, <>, <>---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 + 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 + 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 <> to request allocation of an object with at least +<[nbytes]> bytes of storage available and is 16-byte aligned. If the space is +available, <> returns a pointer to a newly allocated block as its result. + +If you already have a block of storage allocated by <>, but +you no longer need all the space allocated to it, you can make it +smaller by calling <> with both the object pointer and the +new desired size as arguments. <> 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 <> to +request the larger size; again, <> 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 <> +or <> (or the related function <>), return it to the +memory storage pool by calling <> with the address of the object +as the argument. You can also use <> 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 +<>, 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 +<> returns a pointer to the newly allocated space, if +successful; otherwise it returns <>. If your application needs +to generate empty objects, you may use <> for this purpose. + +<> returns a pointer to the new block of memory, or <> +if a new block could not be allocated. <> is also the result +when you use `<,0)>>' (which has the same effect as +`<)>>'). You should always check the result of +<>; successful vec_reallocation is not guaranteed even when +you request a smaller object. + +<> does not return a result. + +PORTABILITY +<>, <>, and <> are all extensions +specified in the AltiVec Programming Interface Manual. + +Supporting OS subroutines required: <>. */ + +#include <_ansi.h> +#include +#include +#include + +#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 /* for size_t */ +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + 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 +#include +#include + +#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 +#include + +#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 +<>, <>, <>---format argument list + +INDEX + vprintf +INDEX + vfprintf +INDEX + vsprintf +INDEX + vsnprintf + +ANSI_SYNOPSIS + #include + #include + 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 + #include + 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 +<>, <>, <> and <> are (respectively) +variants of <>, <>, <> and <>. They differ +only in allowing their caller to pass the variable argument list as a +<> object (initialized by <>) rather than directly +accepting a variable number of arguments. + +RETURNS +The return values are consistent with the corresponding functions: +<> returns the number of bytes in the output string, +save that the concluding <> is not counted. +<> and <> return the number of characters transmitted. +If an error occurs, <> and <> return <>. No +error returns occur for <>. + +PORTABILITY +ANSI C requires all three functions. + +Supporting OS subroutines required: <>, <>, <>, +<>, <>, <>, <>. +*/ + +/*- + * 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 +#include +#include +#include +#include +#ifdef __ALTIVEC__ +#include +#endif + +#ifdef _HAVE_STDC +#include +#else +#include +#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 +#include +#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 +<>, <>, <>---format argument list + +INDEX + vscanf +INDEX + vfscanf +INDEX + vsscanf + +ANSI_SYNOPSIS + #include + #include + 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 + #include + 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 +<>, <>, and <> are (respectively) variants +of <>, <>, and <>. They differ only in +allowing their caller to pass the variable argument list as a +<> object (initialized by <>) rather than +directly accepting a variable number of arguments. + +RETURNS +The return values are consistent with the corresponding functions: +<> returns the number of input fields successfully scanned, +converted, and stored; the return value does not include scanned +fields which were not stored. + +If <> attempts to read at end-of-file, the return value +is <>. + +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 +#include +#include +#include +#ifdef _HAVE_STDC +#include +#else +#include +#endif +#include "local.h" + +#ifndef NO_FLOATING_POINT +#define FLOATING_POINT +#endif + +#ifdef FLOATING_POINT +#include + +/* 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 */ +}