676 lines
18 KiB
C
676 lines
18 KiB
C
/*
|
|
* 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. 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.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2012-2014 ARM Ltd
|
|
* All rights reserved.
|
|
*
|
|
* 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. The name of the company may not be used to endorse or promote
|
|
* products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD 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.
|
|
*/
|
|
|
|
/*
|
|
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>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
#include <stdint.h>
|
|
#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"
|
|
|
|
|
|
/* GCC PR 14577 at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14557 */
|
|
#if __STDC_VERSION__ >= 201112L
|
|
#define va_ptr(ap) _Generic(&(ap), va_list *: &(ap), default: (va_list *)(ap))
|
|
#elif __GNUC__ >= 4
|
|
#define va_ptr(ap) __builtin_choose_expr(__builtin_types_compatible_p(__typeof__(&(ap)), va_list *), &(ap), (va_list *)(ap))
|
|
#else
|
|
#define va_ptr(ap) (sizeof(ap) == sizeof(va_list) ? (va_list *)&(ap) : (va_list *)(ap))
|
|
#endif
|
|
|
|
/* The __ssputs_r function is shared between all versions of vfprintf
|
|
and vfwprintf. */
|
|
#ifdef STRING_ONLY
|
|
int
|
|
_DEFUN(__ssputs_r, (ptr, fp, buf, len),
|
|
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
|
|
_DEFUN(__ssprint_r, (ptr, fp, uio),
|
|
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
|
|
_DEFUN(__sprint_r, (ptr, fp, uio),
|
|
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
|
|
_DEFUN(__sfputc_r, (ptr, c, fp),
|
|
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));
|
|
}
|
|
|
|
int
|
|
_DEFUN(__sfputs_r, (ptr, fp, buf, len),
|
|
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 _EXFUN(_VFPRINTF_R, (struct _reent *, FILE *, const char *, va_list));
|
|
|
|
#ifndef STRING_ONLY
|
|
int
|
|
_DEFUN(VFPRINTF, (fp, fmt0, ap),
|
|
FILE * fp,
|
|
const char *fmt0,
|
|
va_list ap)
|
|
{
|
|
int result;
|
|
result = _VFPRINTF_R (_REENT, fp, fmt0, ap);
|
|
return result;
|
|
}
|
|
|
|
int
|
|
_EXFUN(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
|
|
_DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap),
|
|
struct _reent *data,
|
|
FILE * fp,
|
|
const char *fmt0,
|
|
va_list ap)
|
|
{
|
|
register char *fmt; /* Format string. */
|
|
register int n, m; /* Handy integers (short term usage). */
|
|
register char *cp; /* Handy char pointer (short term usage). */
|
|
const char *flag_chars;
|
|
struct _prt_data_t prt_data; /* All data for decoding format string. */
|
|
|
|
/* 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
|
|
|
|
fmt = (char *)fmt0;
|
|
prt_data.ret = 0;
|
|
prt_data.blank = ' ';
|
|
prt_data.zero = '0';
|
|
|
|
/* Scan the format for conversions (`%' character). */
|
|
for (;;)
|
|
{
|
|
cp = fmt;
|
|
while (*fmt != '\0' && *fmt != '%')
|
|
fmt += 1;
|
|
|
|
if ((m = fmt - cp) != 0)
|
|
{
|
|
PRINT (cp, m);
|
|
prt_data.ret += m;
|
|
}
|
|
if (*fmt == '\0')
|
|
goto done;
|
|
|
|
fmt++; /* Skip over '%'. */
|
|
|
|
prt_data.flags = 0;
|
|
prt_data.width = 0;
|
|
prt_data.prec = -1;
|
|
prt_data.dprec = 0;
|
|
prt_data.l_buf[0] = '\0';
|
|
#ifdef FLOATING_POINT
|
|
prt_data.lead = 0;
|
|
#endif
|
|
/* The flags. */
|
|
/*
|
|
* ``Note that 0 is taken as a flag, not as the
|
|
* beginning of a field width.''
|
|
* -- ANSI X3J11
|
|
*/
|
|
flag_chars = "#-0+ ";
|
|
for (; cp = memchr (flag_chars, *fmt, 5); fmt++)
|
|
prt_data.flags |= (1 << (cp - flag_chars));
|
|
|
|
if (prt_data.flags & SPACESGN)
|
|
prt_data.l_buf[0] = ' ';
|
|
|
|
/*
|
|
* ``If the space and + flags both appear, the space
|
|
* flag will be ignored.''
|
|
* -- ANSI X3J11
|
|
*/
|
|
if (prt_data.flags & PLUSSGN)
|
|
prt_data.l_buf[0] = '+';
|
|
|
|
/* The width. */
|
|
if (*fmt == '*')
|
|
{
|
|
/*
|
|
* ``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.
|
|
*/
|
|
prt_data.width = GET_ARG (n, ap, int);
|
|
if (prt_data.width < 0)
|
|
{
|
|
prt_data.width = -prt_data.width;
|
|
prt_data.flags |= LADJUST;
|
|
}
|
|
fmt++;
|
|
}
|
|
else
|
|
{
|
|
for (; is_digit (*fmt); fmt++)
|
|
prt_data.width = 10 * prt_data.width + to_digit (*fmt);
|
|
}
|
|
|
|
/* The precision. */
|
|
if (*fmt == '.')
|
|
{
|
|
fmt++;
|
|
if (*fmt == '*')
|
|
{
|
|
fmt++;
|
|
prt_data.prec = GET_ARG (n, ap, int);
|
|
if (prt_data.prec < 0)
|
|
prt_data.prec = -1;
|
|
}
|
|
else
|
|
{
|
|
prt_data.prec = 0;
|
|
for (; is_digit (*fmt); fmt++)
|
|
prt_data.prec = 10 * prt_data.prec + to_digit (*fmt);
|
|
}
|
|
}
|
|
|
|
/* The length modifiers. */
|
|
flag_chars = "hlL";
|
|
if ((cp = memchr (flag_chars, *fmt, 3)) != NULL)
|
|
{
|
|
prt_data.flags |= (SHORTINT << (cp - flag_chars));
|
|
fmt++;
|
|
}
|
|
|
|
/* The conversion specifiers. */
|
|
prt_data.code = *fmt++;
|
|
cp = memchr ("efgEFG", prt_data.code, 6);
|
|
#ifdef FLOATING_POINT
|
|
/* If cp is not NULL, we are facing FLOATING POINT NUMBER. */
|
|
if (cp)
|
|
{
|
|
/* Consume floating point argument if _printf_float is not
|
|
linked. */
|
|
if (_printf_float == NULL)
|
|
{
|
|
if (prt_data.flags & LONGDBL)
|
|
GET_ARG (N, ap, _LONG_DOUBLE);
|
|
else
|
|
GET_ARG (N, ap, double);
|
|
}
|
|
else
|
|
{
|
|
n = _printf_float (data, &prt_data, fp, pfunc, va_ptr(ap));
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
n = _printf_i (data, &prt_data, fp, pfunc, va_ptr(ap));
|
|
|
|
if (n == -1)
|
|
goto error;
|
|
|
|
prt_data.ret += n;
|
|
}
|
|
done:
|
|
FLUSH ();
|
|
error:
|
|
#ifndef STRING_ONLY
|
|
_newlib_flockfile_end (fp);
|
|
#endif
|
|
return (__sferror (fp) ? EOF : prt_data.ret);
|
|
}
|
|
|
|
#ifdef STRING_ONLY
|
|
int
|
|
_EXFUN(_svfiprintf_r, (struct _reent *, FILE *, const char *, __VALIST)
|
|
_ATTRIBUTE ((__alias__("_svfprintf_r"))));
|
|
#else
|
|
int
|
|
_EXFUN(_vfiprintf_r, (struct _reent *, FILE *, const char *, __VALIST)
|
|
_ATTRIBUTE ((__alias__("_vfprintf_r"))));
|
|
#endif
|