Implement reduced code size "tiny" printf and puts
"tiny" printf is derived from _vfprintf_r in libc/stdio/nano-vfprintf.c. "tiny" puts has been implemented so that it just calls write, without any other processing. Support for buffering, reentrancy and streams has been removed from these functions to achieve reduced code size. This reduced code size implementation of printf and puts can be enabled in an application by passing "--wrap printf" and "--wrap puts" to the GNU linker. This will replace references to "printf" and "puts" in user code with "__wrap_printf" and "__wrap_puts" respectively. If there is no implementation of these __wrap* functions in user code, these "tiny" printf and puts implementations will be linked into the final executable. The wrapping mechanism is supposed to be invisible to the user: - A GCC wrapper option such as "-mtiny-printf" will be added to alias these wrap commands. - If the user is unaware of the "tiny" implementation, and chooses to implement their own __wrap_printf and __wrap_puts, their own implementation will be automatically chosen over the "tiny" printf and puts from the library. Newlib must be configured with --enable-newlib-nano-formatted-io for the "tiny" printf and puts functions to be built into the library. Code size reduction examples: printf("Hello World\n") baseline - msp430-elf-gcc gcc-8_3_0-release text data bss 5638 214 26 "tiny" puts enabled text data bss 714 90 20 printf("Hello %d\n", a) baseline - msp430-elf-gcc gcc-8_3_0-release text data bss 10916 614 28 "tiny" printf enabled text data bss 4632 280 20
This commit is contained in:
parent
2af6ad9f05
commit
1e6c561d48
|
@ -21,9 +21,16 @@ AM_CCASFLAGS = $(INCLUDES)
|
|||
|
||||
noinst_LIBRARIES = lib.a
|
||||
|
||||
lib_a_SOURCES = setjmp.S
|
||||
lib_a_SOURCES = setjmp.S $(TINY_SOURCES)
|
||||
lib_a_CCASFLAGS=$(AM_CCASFLAGS)
|
||||
lib_a_CFLAGS=$(AM_CFLAGS)
|
||||
|
||||
# tiny-printf.c and tiny-puts.c are derived from the nano printf/puts
|
||||
# functions, so other supporting nano functions are required, and the tiny
|
||||
# printf/puts will not work without them.
|
||||
if NEWLIB_NANO_FORMATTED_IO
|
||||
TINY_SOURCES = tiny-puts.c tiny-printf.c
|
||||
endif
|
||||
|
||||
ACLOCAL_AMFLAGS = -I ../../.. -I ../../../..
|
||||
CONFIG_STATUS_DEPENDENCIES = $(newlib_basedir)/configure.host
|
||||
|
|
|
@ -82,7 +82,10 @@ LIBRARIES = $(noinst_LIBRARIES)
|
|||
ARFLAGS = cru
|
||||
lib_a_AR = $(AR) $(ARFLAGS)
|
||||
lib_a_LIBADD =
|
||||
am_lib_a_OBJECTS = lib_a-setjmp.$(OBJEXT)
|
||||
@NEWLIB_NANO_FORMATTED_IO_TRUE@am__objects_1 = \
|
||||
@NEWLIB_NANO_FORMATTED_IO_TRUE@ lib_a-tiny-puts.$(OBJEXT) \
|
||||
@NEWLIB_NANO_FORMATTED_IO_TRUE@ lib_a-tiny-printf.$(OBJEXT)
|
||||
am_lib_a_OBJECTS = lib_a-setjmp.$(OBJEXT) $(am__objects_1)
|
||||
lib_a_OBJECTS = $(am_lib_a_OBJECTS)
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@
|
||||
depcomp =
|
||||
|
@ -195,6 +198,7 @@ pdfdir = @pdfdir@
|
|||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
|
@ -208,15 +212,20 @@ AUTOMAKE_OPTIONS = cygnus
|
|||
INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS)
|
||||
AM_CCASFLAGS = $(INCLUDES)
|
||||
noinst_LIBRARIES = lib.a
|
||||
lib_a_SOURCES = setjmp.S
|
||||
lib_a_SOURCES = setjmp.S $(TINY_SOURCES)
|
||||
lib_a_CCASFLAGS = $(AM_CCASFLAGS)
|
||||
lib_a_CFLAGS = $(AM_CFLAGS)
|
||||
|
||||
# tiny-printf.c and tiny-puts.c are derived from the nano printf/puts
|
||||
# functions, so other supporting nano functions are required, and the tiny
|
||||
# printf/puts will not work without them.
|
||||
@NEWLIB_NANO_FORMATTED_IO_TRUE@TINY_SOURCES = tiny-puts.c tiny-printf.c
|
||||
ACLOCAL_AMFLAGS = -I ../../.. -I ../../../..
|
||||
CONFIG_STATUS_DEPENDENCIES = $(newlib_basedir)/configure.host
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .S .o .obj
|
||||
.SUFFIXES: .S .c .o .obj
|
||||
am--refresh: Makefile
|
||||
@:
|
||||
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
|
@ -277,6 +286,24 @@ lib_a-setjmp.o: setjmp.S
|
|||
lib_a-setjmp.obj: setjmp.S
|
||||
$(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CCASFLAGS) $(CCASFLAGS) -c -o lib_a-setjmp.obj `if test -f 'setjmp.S'; then $(CYGPATH_W) 'setjmp.S'; else $(CYGPATH_W) '$(srcdir)/setjmp.S'; fi`
|
||||
|
||||
.c.o:
|
||||
$(COMPILE) -c $<
|
||||
|
||||
.c.obj:
|
||||
$(COMPILE) -c `$(CYGPATH_W) '$<'`
|
||||
|
||||
lib_a-tiny-puts.o: tiny-puts.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-tiny-puts.o `test -f 'tiny-puts.c' || echo '$(srcdir)/'`tiny-puts.c
|
||||
|
||||
lib_a-tiny-puts.obj: tiny-puts.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-tiny-puts.obj `if test -f 'tiny-puts.c'; then $(CYGPATH_W) 'tiny-puts.c'; else $(CYGPATH_W) '$(srcdir)/tiny-puts.c'; fi`
|
||||
|
||||
lib_a-tiny-printf.o: tiny-printf.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-tiny-printf.o `test -f 'tiny-printf.c' || echo '$(srcdir)/'`tiny-printf.c
|
||||
|
||||
lib_a-tiny-printf.obj: tiny-printf.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-tiny-printf.obj `if test -f 'tiny-printf.c'; then $(CYGPATH_W) 'tiny-printf.c'; else $(CYGPATH_W) '$(srcdir)/tiny-printf.c'; fi`
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
|
|
|
@ -640,6 +640,8 @@ build
|
|||
newlib_basedir
|
||||
MAY_SUPPLY_SYSCALLS_FALSE
|
||||
MAY_SUPPLY_SYSCALLS_TRUE
|
||||
NEWLIB_NANO_FORMATTED_IO_FALSE
|
||||
NEWLIB_NANO_FORMATTED_IO_TRUE
|
||||
target_alias
|
||||
host_alias
|
||||
build_alias
|
||||
|
@ -681,6 +683,7 @@ SHELL'
|
|||
ac_subst_files=''
|
||||
ac_user_opts='
|
||||
enable_option_checking
|
||||
enable_newlib_nano_formatted_io
|
||||
enable_multilib
|
||||
enable_target_optspace
|
||||
enable_malloc_debugging
|
||||
|
@ -1318,6 +1321,7 @@ Optional Features:
|
|||
--disable-option-checking ignore unrecognized --enable/--with options
|
||||
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
|
||||
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
|
||||
--enable-newlib-nano-formatted-io Use small-footprint nano-formatted-IO implementation
|
||||
--enable-multilib build many library versions (default)
|
||||
--enable-target-optspace optimize for space
|
||||
--enable-malloc-debugging indicate malloc debugging requested
|
||||
|
@ -1837,6 +1841,26 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
|
|||
|
||||
|
||||
|
||||
# Check whether --enable-newlib_nano_formatted_io was given.
|
||||
if test "${enable_newlib_nano_formatted_io+set}" = set; then :
|
||||
enableval=$enable_newlib_nano_formatted_io; case "${enableval}" in
|
||||
yes) newlib_nano_formatted_io=yes ;;
|
||||
no) newlib_nano_formatted_io=no ;;
|
||||
*) as_fn_error $? "bad value ${enableval} for newlib-nano-formatted-io" "$LINENO" 5 ;;
|
||||
esac
|
||||
else
|
||||
newlib_nano_formatted_io=no
|
||||
fi
|
||||
|
||||
if test x$newlib_nano_formatted_io = xyes; then
|
||||
NEWLIB_NANO_FORMATTED_IO_TRUE=
|
||||
NEWLIB_NANO_FORMATTED_IO_FALSE='#'
|
||||
else
|
||||
NEWLIB_NANO_FORMATTED_IO_TRUE='#'
|
||||
NEWLIB_NANO_FORMATTED_IO_FALSE=
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# Make sure we can run config.sub.
|
||||
$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
|
||||
|
@ -3575,6 +3599,10 @@ LIBOBJS=$ac_libobjs
|
|||
LTLIBOBJS=$ac_ltlibobjs
|
||||
|
||||
|
||||
if test -z "${NEWLIB_NANO_FORMATTED_IO_TRUE}" && test -z "${NEWLIB_NANO_FORMATTED_IO_FALSE}"; then
|
||||
as_fn_error $? "conditional \"NEWLIB_NANO_FORMATTED_IO\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
fi
|
||||
if test -z "${MAY_SUPPLY_SYSCALLS_TRUE}" && test -z "${MAY_SUPPLY_SYSCALLS_FALSE}"; then
|
||||
as_fn_error $? "conditional \"MAY_SUPPLY_SYSCALLS\" was never defined.
|
||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||
|
|
|
@ -21,6 +21,17 @@ AC_CONFIG_SRCDIR([setjmp.S])
|
|||
dnl Can't be done in NEWLIB_CONFIGURE because that confuses automake.
|
||||
AC_CONFIG_AUX_DIR(../../../..)
|
||||
|
||||
dnl Support --enable-newlib-nano-formatted-io required by tiny-printf.c
|
||||
dnl and tiny-puts.c
|
||||
AC_ARG_ENABLE(newlib_nano_formatted_io,
|
||||
[ --enable-newlib-nano-formatted-io Use small-footprint nano-formatted-IO implementation],
|
||||
[case "${enableval}" in
|
||||
yes) newlib_nano_formatted_io=yes ;;
|
||||
no) newlib_nano_formatted_io=no ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for newlib-nano-formatted-io) ;;
|
||||
esac],[newlib_nano_formatted_io=no])
|
||||
AM_CONDITIONAL(NEWLIB_NANO_FORMATTED_IO, test x$newlib_nano_formatted_io = xyes)
|
||||
|
||||
NEWLIB_CONFIGURE(../../..)
|
||||
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
|
|
|
@ -58,100 +58,11 @@
|
|||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
FUNCTION
|
||||
<<vfprintf>>, <<vprintf>>, <<vsprintf>>, <<vsnprintf>>, <<vasprintf>>, <<vasnprintf>>---format argument list
|
||||
|
||||
INDEX
|
||||
vfprintf
|
||||
INDEX
|
||||
_vfprintf_r
|
||||
INDEX
|
||||
vprintf
|
||||
INDEX
|
||||
_vprintf_r
|
||||
INDEX
|
||||
vsprintf
|
||||
INDEX
|
||||
_vsprintf_r
|
||||
INDEX
|
||||
vsnprintf
|
||||
INDEX
|
||||
_vsnprintf_r
|
||||
INDEX
|
||||
vasprintf
|
||||
INDEX
|
||||
_vasprintf_r
|
||||
INDEX
|
||||
vasnprintf
|
||||
INDEX
|
||||
_vasnprintf_r
|
||||
|
||||
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 vasprintf(char **<[strp]>, const char *<[fmt]>, va_list <[list]>);
|
||||
char *vasnprintf(char *<[str]>, size_t *<[size]>, const char *<[fmt]>,
|
||||
va_list <[list]>);
|
||||
|
||||
int _vprintf_r(struct _reent *<[reent]>, const char *<[fmt]>,
|
||||
va_list <[list]>);
|
||||
int _vfprintf_r(struct _reent *<[reent]>, FILE *<[fp]>,
|
||||
const char *<[fmt]>, va_list <[list]>);
|
||||
int _vsprintf_r(struct _reent *<[reent]>, char *<[str]>,
|
||||
const char *<[fmt]>, va_list <[list]>);
|
||||
int _vasprintf_r(struct _reent *<[reent]>, char **<[str]>,
|
||||
const char *<[fmt]>, va_list <[list]>);
|
||||
int _vsnprintf_r(struct _reent *<[reent]>, char *<[str]>,
|
||||
size_t <[size]>, const char *<[fmt]>, va_list <[list]>);
|
||||
char *_vasnprintf_r(struct _reent *<[reent]>, char *<[str]>,
|
||||
size_t *<[size]>, const char *<[fmt]>, va_list <[list]>);
|
||||
|
||||
DESCRIPTION
|
||||
<<vprintf>>, <<vfprintf>>, <<vasprintf>>, <<vsprintf>>, <<vsnprintf>>,
|
||||
and <<vasnprintf>> are (respectively) variants of <<printf>>,
|
||||
<<fprintf>>, <<asprintf>>, <<sprintf>>, <<snprintf>>, and
|
||||
<<asnprintf>>. 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. The caller is responsible for calling <<va_end>>.
|
||||
|
||||
<<_vprintf_r>>, <<_vfprintf_r>>, <<_vasprintf_r>>, <<_vsprintf_r>>,
|
||||
<<_vsnprintf_r>>, and <<_vasnprintf_r>> are reentrant versions of the
|
||||
above.
|
||||
|
||||
RETURNS
|
||||
The return values are consistent with the corresponding functions.
|
||||
|
||||
PORTABILITY
|
||||
ANSI C requires <<vprintf>>, <<vfprintf>>, <<vsprintf>>, and
|
||||
<<vsnprintf>>. The remaining functions are newlib extensions.
|
||||
|
||||
Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
|
||||
<<lseek>>, <<read>>, <<sbrk>>, <<write>>.
|
||||
*/
|
||||
|
||||
#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... */
|
||||
#include <newlib.h>
|
||||
|
||||
#define VFPRINTF vfprintf
|
||||
#ifdef STRING_ONLY
|
||||
# define _VFPRINTF_R _svfprintf_r
|
||||
#else
|
||||
# define _VFPRINTF_R _vfprintf_r
|
||||
#endif
|
||||
|
||||
#include <_ansi.h>
|
||||
#include <reent.h>
|
||||
#include <stdio.h>
|
||||
|
@ -162,310 +73,35 @@ static char *rcsid = "$Id$";
|
|||
#include <wchar.h>
|
||||
#include <sys/lock.h>
|
||||
#include <stdarg.h>
|
||||
#include "local.h"
|
||||
#include "../stdlib/local.h"
|
||||
#include "fvwrite.h"
|
||||
#include "vfieeefp.h"
|
||||
#include "nano-vfprintf_local.h"
|
||||
#include <string.h>
|
||||
#include <newlib.h>
|
||||
#include "../../stdio/local.h"
|
||||
#include "../../stdlib/local.h"
|
||||
#include "../../stdio/fvwrite.h"
|
||||
#include "../../stdio/nano-vfprintf_local.h"
|
||||
|
||||
/* The __ssputs_r function is shared between all versions of vfprintf
|
||||
and vfwprintf. */
|
||||
#ifdef STRING_ONLY
|
||||
/* Bypass *putc* fns called by the default _sfputs_r to save code size.
|
||||
Among other things, this means there is no buffering of the string before
|
||||
it is sent to <<write>>, but <<write>> does its own buffering so we won't
|
||||
lose chars when buf is larger than sizeof(CIOBUF). */
|
||||
int
|
||||
__ssputs_r (struct _reent *ptr,
|
||||
__tiny__sfputs_r (struct _reent *ptr,
|
||||
FILE *fp,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
register int w;
|
||||
|
||||
w = fp->_w;
|
||||
if (len >= w && fp->_flags & (__SMBF | __SOPT))
|
||||
{
|
||||
/* Must be asprintf family. */
|
||||
unsigned char *str;
|
||||
int curpos = (fp->_p - fp->_bf._base);
|
||||
/* Choose a geometric growth factor to avoid
|
||||
* quadratic realloc behavior, but use a rate less
|
||||
* than (1+sqrt(5))/2 to accomodate malloc
|
||||
* overhead. asprintf EXPECTS us to overallocate, so
|
||||
* that it can add a trailing \0 without
|
||||
* reallocating. The new allocation should thus be
|
||||
* max(prev_size*1.5, curpos+len+1). */
|
||||
int newsize = fp->_bf._size * 3 / 2;
|
||||
if (newsize < curpos + len + 1)
|
||||
newsize = curpos + len + 1;
|
||||
if (fp->_flags & __SOPT)
|
||||
{
|
||||
/* asnprintf leaves original buffer alone. */
|
||||
str = (unsigned char *)_malloc_r (ptr, newsize);
|
||||
if (!str)
|
||||
{
|
||||
ptr->_errno = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
memcpy (str, fp->_bf._base, curpos);
|
||||
fp->_flags = (fp->_flags & ~__SOPT) | __SMBF;
|
||||
}
|
||||
else
|
||||
{
|
||||
str = (unsigned char *)_realloc_r (ptr, fp->_bf._base, newsize);
|
||||
if (!str)
|
||||
{
|
||||
/* Free unneeded buffer. */
|
||||
_free_r (ptr, fp->_bf._base);
|
||||
/* Ensure correct errno, even if free changed it. */
|
||||
ptr->_errno = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
fp->_bf._base = str;
|
||||
fp->_p = str + curpos;
|
||||
fp->_bf._size = newsize;
|
||||
w = len;
|
||||
fp->_w = newsize - curpos;
|
||||
}
|
||||
if (len < w)
|
||||
w = len;
|
||||
|
||||
(void)memmove ((void *) fp->_p, (void *) buf, (size_t) (w));
|
||||
fp->_w -= w;
|
||||
fp->_p += w;
|
||||
return 0;
|
||||
|
||||
err:
|
||||
fp->_flags |= __SERR;
|
||||
return EOF;
|
||||
}
|
||||
/* __ssprint_r is the original implementation of __SPRINT. In nano
|
||||
version formatted IO it is reimplemented as __ssputs_r for non-wide
|
||||
char output, but __ssprint_r cannot be discarded because it is used
|
||||
by a serial of functions like svfwprintf for wide char output. */
|
||||
int
|
||||
__ssprint_r (struct _reent *ptr,
|
||||
FILE *fp,
|
||||
register struct __suio *uio)
|
||||
{
|
||||
register size_t len;
|
||||
register int w;
|
||||
register struct __siov *iov;
|
||||
register const char *p = NULL;
|
||||
|
||||
iov = uio->uio_iov;
|
||||
len = 0;
|
||||
|
||||
if (uio->uio_resid == 0)
|
||||
{
|
||||
uio->uio_iovcnt = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
while (len == 0)
|
||||
{
|
||||
p = iov->iov_base;
|
||||
len = iov->iov_len;
|
||||
iov++;
|
||||
}
|
||||
w = fp->_w;
|
||||
if (len >= w && fp->_flags & (__SMBF | __SOPT))
|
||||
{
|
||||
/* Must be asprintf family. */
|
||||
unsigned char *str;
|
||||
int curpos = (fp->_p - fp->_bf._base);
|
||||
/* Choose a geometric growth factor to avoid
|
||||
* quadratic realloc behavior, but use a rate less
|
||||
* than (1+sqrt(5))/2 to accomodate malloc
|
||||
* overhead. asprintf EXPECTS us to overallocate, so
|
||||
* that it can add a trailing \0 without
|
||||
* reallocating. The new allocation should thus be
|
||||
* max(prev_size*1.5, curpos+len+1). */
|
||||
int newsize = fp->_bf._size * 3 / 2;
|
||||
if (newsize < curpos + len + 1)
|
||||
newsize = curpos + len + 1;
|
||||
|
||||
if (fp->_flags & __SOPT)
|
||||
{
|
||||
/* asnprintf leaves original buffer alone. */
|
||||
str = (unsigned char *)_malloc_r (ptr, newsize);
|
||||
if (!str)
|
||||
{
|
||||
ptr->_errno = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
memcpy (str, fp->_bf._base, curpos);
|
||||
fp->_flags = (fp->_flags & ~__SOPT) | __SMBF;
|
||||
}
|
||||
else
|
||||
{
|
||||
str = (unsigned char *)_realloc_r (ptr, fp->_bf._base,
|
||||
newsize);
|
||||
if (!str)
|
||||
{
|
||||
/* Free unneeded buffer. */
|
||||
_free_r (ptr, fp->_bf._base);
|
||||
/* Ensure correct errno, even if free changed it. */
|
||||
ptr->_errno = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
fp->_bf._base = str;
|
||||
fp->_p = str + curpos;
|
||||
fp->_bf._size = newsize;
|
||||
w = len;
|
||||
fp->_w = newsize - curpos;
|
||||
}
|
||||
if (len < w)
|
||||
w = len;
|
||||
|
||||
(void)memmove ((void *) fp->_p, (void *) p, (size_t) (w));
|
||||
fp->_w -= w;
|
||||
fp->_p += w;
|
||||
/* Pretend we copied all. */
|
||||
w = len;
|
||||
p += w;
|
||||
len -= w;
|
||||
}
|
||||
while ((uio->uio_resid -= w) != 0);
|
||||
|
||||
uio->uio_resid = 0;
|
||||
uio->uio_iovcnt = 0;
|
||||
return 0;
|
||||
|
||||
err:
|
||||
fp->_flags |= __SERR;
|
||||
uio->uio_resid = 0;
|
||||
uio->uio_iovcnt = 0;
|
||||
return EOF;
|
||||
}
|
||||
#else
|
||||
/* As __ssputs_r, __sprint_r is used by output functions for wide char,
|
||||
like vfwprint. */
|
||||
/* Flush out all the vectors defined by the given uio,
|
||||
then reset it so that it can be reused. */
|
||||
int
|
||||
__sprint_r (struct _reent *ptr,
|
||||
FILE *fp,
|
||||
register struct __suio *uio)
|
||||
{
|
||||
register int err = 0;
|
||||
|
||||
if (uio->uio_resid == 0)
|
||||
{
|
||||
uio->uio_iovcnt = 0;
|
||||
return 0;
|
||||
}
|
||||
#ifdef _WIDE_ORIENT
|
||||
if (fp->_flags2 & __SWID)
|
||||
{
|
||||
struct __siov *iov;
|
||||
wchar_t *p;
|
||||
int i, len;
|
||||
|
||||
iov = uio->uio_iov;
|
||||
for (; uio->uio_resid != 0;
|
||||
uio->uio_resid -= len * sizeof (wchar_t), iov++)
|
||||
{
|
||||
p = (wchar_t *) iov->iov_base;
|
||||
len = iov->iov_len / sizeof (wchar_t);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (_fputwc_r (ptr, p[i], fp) == WEOF)
|
||||
{
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
err = __sfvwrite_r(ptr, fp, uio);
|
||||
out:
|
||||
uio->uio_resid = 0;
|
||||
uio->uio_iovcnt = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
_NOINLINE_STATIC int
|
||||
__sfputc_r (struct _reent *ptr,
|
||||
int c,
|
||||
FILE *fp)
|
||||
{
|
||||
if (--fp->_w >= 0 || (fp->_w >= fp->_lbfsize && (char)c != '\n'))
|
||||
return (*fp->_p++ = c);
|
||||
else
|
||||
return (__swbuf_r(ptr, c, fp));
|
||||
return write (1, buf, len);
|
||||
}
|
||||
|
||||
/* VFPRINTF_R from nano-vfprintf.c but:
|
||||
- No support for reentrancy
|
||||
- No support for streams
|
||||
- __SINGLE_THREAD__ assumed.
|
||||
- No STRING_ONLY variant (either way the formatted string would end up
|
||||
being sent to <<write>> via <<__tiny__sfputs_r>>.
|
||||
Basically, format the string as normal, and send it to write. */
|
||||
int
|
||||
__sfputs_r (struct _reent *ptr,
|
||||
FILE *fp,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
register int i;
|
||||
|
||||
#ifdef _WIDE_ORIENT
|
||||
if (fp->_flags2 & __SWID)
|
||||
{
|
||||
wchar_t *p;
|
||||
|
||||
p = (wchar_t *) buf;
|
||||
for (i = 0; i < (len / sizeof (wchar_t)); i++)
|
||||
{
|
||||
if (_fputwc_r (ptr, p[i], fp) == WEOF)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
/* Call __sfputc_r to skip _fputc_r. */
|
||||
if (__sfputc_r (ptr, (int)buf[i], fp) == EOF)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
#endif /* STRING_ONLY. */
|
||||
|
||||
int _VFPRINTF_R (struct _reent *, FILE *, const char *, va_list);
|
||||
|
||||
#ifndef STRING_ONLY
|
||||
int
|
||||
VFPRINTF (FILE * fp,
|
||||
const char *fmt0,
|
||||
va_list ap)
|
||||
{
|
||||
int result;
|
||||
result = _VFPRINTF_R (_REENT, fp, fmt0, ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
vfiprintf (FILE *, const char *, __VALIST)
|
||||
_ATTRIBUTE ((__alias__("vfprintf")));
|
||||
#endif
|
||||
|
||||
#ifdef STRING_ONLY
|
||||
# define __SPRINT __ssputs_r
|
||||
#else
|
||||
# define __SPRINT __sfputs_r
|
||||
#endif
|
||||
|
||||
/* Do not need FLUSH for all sprintf functions. */
|
||||
#ifdef STRING_ONLY
|
||||
# define FLUSH()
|
||||
#else
|
||||
# define FLUSH()
|
||||
#endif
|
||||
|
||||
int
|
||||
_VFPRINTF_R (struct _reent *data,
|
||||
__tiny_vfprintf_r (struct _reent *data,
|
||||
FILE * fp,
|
||||
const char *fmt0,
|
||||
va_list ap)
|
||||
|
@ -480,33 +116,7 @@ _VFPRINTF_R (struct _reent *data,
|
|||
/* Output function pointer. */
|
||||
int (*pfunc)(struct _reent *, FILE *, const char *, size_t len);
|
||||
|
||||
pfunc = __SPRINT;
|
||||
|
||||
#ifndef STRING_ONLY
|
||||
/* Initialize std streams if not dealing with sprintf family. */
|
||||
CHECK_INIT (data, fp);
|
||||
_newlib_flockfile_start (fp);
|
||||
|
||||
/* Sorry, fprintf(read_only_file, "") returns EOF, not 0. */
|
||||
if (cantwrite (data, fp))
|
||||
{
|
||||
_newlib_flockfile_exit (fp);
|
||||
return (EOF);
|
||||
}
|
||||
|
||||
#else
|
||||
/* Create initial buffer if we are called by asprintf family. */
|
||||
if (fp->_flags & __SMBF && !fp->_bf._base)
|
||||
{
|
||||
fp->_bf._base = fp->_p = _malloc_r (data, 64);
|
||||
if (!fp->_p)
|
||||
{
|
||||
data->_errno = ENOMEM;
|
||||
return EOF;
|
||||
}
|
||||
fp->_bf._size = 64;
|
||||
}
|
||||
#endif
|
||||
pfunc = __tiny__sfputs_r;
|
||||
|
||||
fmt = (char *)fmt0;
|
||||
prt_data.ret = 0;
|
||||
|
@ -641,21 +251,22 @@ _VFPRINTF_R (struct _reent *data,
|
|||
prt_data.ret += n;
|
||||
}
|
||||
done:
|
||||
FLUSH ();
|
||||
error:
|
||||
#ifndef STRING_ONLY
|
||||
_newlib_flockfile_end (fp);
|
||||
#endif
|
||||
va_end (ap_copy);
|
||||
return (__sferror (fp) ? EOF : prt_data.ret);
|
||||
}
|
||||
|
||||
#ifdef STRING_ONLY
|
||||
int
|
||||
_svfiprintf_r (struct _reent *, FILE *, const char *, __VALIST)
|
||||
_ATTRIBUTE ((__alias__("_svfprintf_r")));
|
||||
#else
|
||||
int
|
||||
_vfiprintf_r (struct _reent *, FILE *, const char *, __VALIST)
|
||||
_ATTRIBUTE ((__alias__("_vfprintf_r")));
|
||||
#endif
|
||||
__wrap_printf (const char *__restrict fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
struct _reent *ptr = _REENT;
|
||||
|
||||
va_start (ap, fmt);
|
||||
ret = __tiny_vfprintf_r (ptr, _stdout_r (ptr), fmt, ap);
|
||||
va_end (ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int printf (const char *__restrict fmt, ...) __attribute__ ((weak, alias ("__wrap_printf")));
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <newlib.h>
|
||||
|
||||
int write (int fd, const char *buf, int len);
|
||||
|
||||
int
|
||||
__wrap_puts (const char * s)
|
||||
{
|
||||
int res = write (1, s, strlen (s));
|
||||
if (res == EOF)
|
||||
{
|
||||
write (1, "\n", 1);
|
||||
return EOF;
|
||||
}
|
||||
return write (1, "\n", 1);
|
||||
}
|
||||
|
||||
int puts (const char * s) __attribute__ ((weak, alias ("__wrap_puts")));
|
Loading…
Reference in New Issue