Reduce stack size of *printf.

* libc/stdio/vfprintf.c (_VFPRINTF_R): Fix use of decimal point
in %f.  Avoid malloc when possible for %S.
(BUF): Improve stack locality by using smaller size.
(MAXEXPLEN, _PRINTF_FLOAT_TYPE): Define.
(exponent): Use smaller stack size.
This commit is contained in:
Eric Blake 2007-05-14 19:42:47 +00:00
parent 7b63e3a697
commit 34507ce026
2 changed files with 92 additions and 102 deletions

View File

@ -1,3 +1,12 @@
2007-05-14 Eric Blake <ebb9@byu.net>
Reduce stack size of *printf.
* libc/stdio/vfprintf.c (_VFPRINTF_R): Fix use of decimal point
in %f. Avoid malloc when possible for %S.
(BUF): Improve stack locality by using smaller size.
(MAXEXPLEN, _PRINTF_FLOAT_TYPE): Define.
(exponent): Use smaller stack size.
2007-05-11 Eric Blake <ebb9@byu.net> 2007-05-11 Eric Blake <ebb9@byu.net>
Minimize printf/scanf size on platforms that don't need C99. Minimize printf/scanf size on platforms that don't need C99.

View File

@ -224,43 +224,66 @@ _DEFUN(__sbprintf, (rptr, fp, fmt, ap),
#ifdef FLOATING_POINT #ifdef FLOATING_POINT
#include <locale.h> # include <locale.h>
#include <math.h> # include <math.h>
#include "floatio.h"
#if ((MAXEXP+MAXFRACT+1) > MB_LEN_MAX) /* For %La, an exponent of 15 bits occupies the exponent character, a
# define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */ sign, and up to 5 digits. */
#else # define MAXEXPLEN 7
# define BUF MB_LEN_MAX # define DEFPREC 6
#endif
#define DEFPREC 6 # ifdef _NO_LONGDBL
extern char *_dtoa_r _PARAMS((struct _reent *, double, int,
int, int *, int *, char **));
# define _PRINTF_FLOAT_TYPE double
# define _DTOA_R _dtoa_r
# define FREXP frexp
# else /* !_NO_LONGDBL */
extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int,
int, int *, int *, char **));
#ifdef _NO_LONGDBL
static char *
_EXFUN(cvt, (struct _reent *, double, int, int, char *, int *, int, int *,
char *));
#else
static char *
_EXFUN(cvt, (struct _reent *, _LONG_DOUBLE, int, int, char *, int *, int,
int *, char *));
extern int _EXFUN(_ldcheck,(_LONG_DOUBLE *)); extern int _EXFUN(_ldcheck,(_LONG_DOUBLE *));
#endif
static int _EXFUN(exponent, (char *, int, int)); # define _PRINTF_FLOAT_TYPE _LONG_DOUBLE
# define _DTOA_R _ldtoa_r
/* FIXME - frexpl is not yet supported; and cvt infloops if (double)f
converts a finite value into infinity. */
/* # define FREXP frexpl */
# define FREXP(f,e) ((_LONG_DOUBLE) frexp ((double)f, e))
# endif /* !_NO_LONGDBL */
#else /* no FLOATING_POINT */ static char *cvt(struct _reent *, _PRINTF_FLOAT_TYPE, int, int, char *, int *,
int, int *, char *);
#define BUF 40 static int exponent(char *, int, int);
#endif /* FLOATING_POINT */ #endif /* FLOATING_POINT */
/* BUF must be big enough for the maximum %#llo (assuming long long is
at most 64 bits, this would be 23 characters), the maximum
multibyte character %C, and the maximum default precision of %La
(assuming long double is at most 128 bits with 113 bits of
mantissa, this would be 29 characters). %e, %f, and %g use
reentrant storage shared with mprec. All other formats that use
buf get by with fewer characters. Making BUF slightly bigger
reduces the need for malloc in %.*a and %S, when large precision or
long strings are processed. */
#define BUF 40
#if defined _MB_CAPABLE && MB_LEN_MAX > BUF
# undef BUF
# define BUF MB_LEN_MAX
#endif
#ifndef _NO_LONGLONG #ifndef _NO_LONGLONG
#define quad_t long long # define quad_t long long
#define u_quad_t unsigned long long # define u_quad_t unsigned long long
#else #else
#define quad_t long # define quad_t long
#define u_quad_t unsigned long # define u_quad_t unsigned long
#endif #endif
typedef quad_t * quad_ptr_t; typedef quad_t * quad_ptr_t;
@ -378,19 +401,13 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap),
#ifdef FLOATING_POINT #ifdef FLOATING_POINT
char *decimal_point = _localeconv_r (data)->decimal_point; char *decimal_point = _localeconv_r (data)->decimal_point;
char softsign; /* temporary negative sign for floats */ char softsign; /* temporary negative sign for floats */
# ifdef _NO_LONGDBL union { int i; _PRINTF_FLOAT_TYPE fp; } _double_ = {0};
union { int i; double d; } _double_ = {0}; # define _fpvalue (_double_.fp)
# 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 expt; /* integer value of exponent */
int expsize = 0; /* character count for expstr */ int expsize = 0; /* character count for expstr */
int ndig = 0; /* actual number of digits returned by cvt */ int ndig = 0; /* actual number of digits returned by cvt */
char expstr[7]; /* buffer for exponent string */ char expstr[MAXEXPLEN]; /* buffer for exponent string */
#endif #endif /* FLOATING_POINT */
u_quad_t _uquad; /* integer arguments %[diouxX] */ u_quad_t _uquad; /* integer arguments %[diouxX] */
enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
int dprec; /* a copy of prec if [diouxX], 0 otherwise */ int dprec; /* a copy of prec if [diouxX], 0 otherwise */
@ -400,7 +417,7 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap),
#define NIOV 8 #define NIOV 8
struct __suio uio; /* output information: summary */ struct __suio uio; /* output information: summary */
struct __siov iov[NIOV];/* ... and individual io vectors */ struct __siov iov[NIOV];/* ... and individual io vectors */
char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ char buf[BUF]; /* space for %c, %S, %[diouxX], %[aA] */
char ox[2]; /* space for 0x hex-prefix */ char ox[2]; /* space for 0x hex-prefix */
#ifdef _MB_CAPABLE #ifdef _MB_CAPABLE
wchar_t wc; wchar_t wc;
@ -875,8 +892,8 @@ reswitch: switch (ch) {
} }
/* do this before tricky precision changes */ /* do this before tricky precision changes */
tmp = _ldcheck (&_fpvalue); expt = _ldcheck (&_fpvalue);
if (tmp == 2) { if (expt == 2) {
if (_fpvalue < 0) if (_fpvalue < 0)
sign = '-'; sign = '-';
if (ch <= 'G') /* 'A', 'E', 'F', or 'G' */ if (ch <= 'G') /* 'A', 'E', 'F', or 'G' */
@ -887,7 +904,7 @@ reswitch: switch (ch) {
flags &= ~ZEROPAD; flags &= ~ZEROPAD;
break; break;
} }
if (tmp == 1) { if (expt == 1) {
if (ch <= 'G') /* 'A', 'E', 'F', or 'G' */ if (ch <= 'G') /* 'A', 'E', 'F', or 'G' */
cp = "NAN"; cp = "NAN";
else else
@ -1030,8 +1047,8 @@ reswitch: switch (ch) {
while (1) { while (1) {
if (wcp[m] == L'\0') if (wcp[m] == L'\0')
break; break;
if ((n = (int)_wcrtomb_r (data, if ((n = (int)_wcrtomb_r (data,
buf, wcp[m], &ps)) == -1) { buf, wcp[m], &ps)) == -1) {
fp->_flags |= __SERR; fp->_flags |= __SERR;
goto error; goto error;
} }
@ -1044,31 +1061,35 @@ reswitch: switch (ch) {
} }
} }
else { else {
if ((size = (int)_wcsrtombs_r (data, if ((size = (int)_wcsrtombs_r (data,
NULL, &wcp, 0, &ps)) == -1) { NULL, &wcp, 0, &ps)) == -1) {
fp->_flags |= __SERR; fp->_flags |= __SERR;
goto error; goto error;
} }
wcp = (_CONST wchar_t *)cp; wcp = (_CONST wchar_t *)cp;
} }
if (size == 0) if (size == 0)
break; break;
if ((malloc_buf = if (size >= BUF) {
(char *)_malloc_r (data, size + 1)) == NULL) { if ((malloc_buf =
fp->_flags |= __SERR; (char *)_malloc_r (data, size + 1))
goto error; == NULL) {
} fp->_flags |= __SERR;
goto error;
}
cp = malloc_buf;
} else
cp = buf;
/* Convert widechar string to multibyte string. */ /* Convert widechar string to multibyte string. */
memset ((_PTR)&ps, '\0', sizeof (mbstate_t)); memset ((_PTR)&ps, '\0', sizeof (mbstate_t));
if (_wcsrtombs_r (data, malloc_buf, if (_wcsrtombs_r (data, malloc_buf,
&wcp, size, &ps) != size) { &wcp, size, &ps) != size) {
fp->_flags |= __SERR; fp->_flags |= __SERR;
goto error; goto error;
} }
cp = malloc_buf;
cp[size] = '\0'; cp[size] = '\0';
} }
#endif /* _MB_CAPABLE */ #endif /* _MB_CAPABLE */
@ -1254,11 +1275,11 @@ number: if ((dprec = prec) >= 0)
PRINT (cp, ndig); PRINT (cp, ndig);
PAD (expt - ndig, zeroes); PAD (expt - ndig, zeroes);
if (flags & ALT) if (flags & ALT)
PRINT (".", 1); PRINT (decimal_point, 1);
} else { } else {
PRINT (cp, expt); PRINT (cp, expt);
cp += expt; cp += expt;
PRINT (".", 1); PRINT (decimal_point, 1);
PRINT (cp, ndig - expt); PRINT (cp, ndig - expt);
} }
} else { /* 'a', 'A', 'e', or 'E' */ } else { /* 'a', 'A', 'e', or 'E' */
@ -1305,21 +1326,6 @@ error:
#ifdef FLOATING_POINT #ifdef FLOATING_POINT
# ifdef _NO_LONGDBL
extern char *_dtoa_r _PARAMS((struct _reent *, double, int,
int, int *, int *, char **));
# define _DTOA_R _dtoa_r
# define FREXP frexp
# else
extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int,
int, int *, int *, char **));
# define _DTOA_R _ldtoa_r
/* FIXME - frexpl is not yet supported; and cvt infloops if (double)f
converts a finite value into infinity. */
/* # define FREXP frexpl */
# define FREXP(f,e) ((_LONG_DOUBLE) frexp ((double)f, e))
# endif
/* Using reentrant DATA, convert finite VALUE into a string of digits /* Using reentrant DATA, convert finite VALUE into a string of digits
with no decimal point, using NDIGITS precision and FLAGS as guides with no decimal point, using NDIGITS precision and FLAGS as guides
to whether trailing zeros must be included. Set *SIGN to nonzero to whether trailing zeros must be included. Set *SIGN to nonzero
@ -1327,31 +1333,9 @@ extern char *_ldtoa_r _PARAMS((struct _reent *, _LONG_DOUBLE, int,
*LENGTH to the length of the returned string. CH must be one of *LENGTH to the length of the returned string. CH must be one of
[aAeEfFgG]; if it is [aA], then the return string lives in BUF, [aAeEfFgG]; if it is [aA], then the return string lives in BUF,
otherwise the return value shares the mprec reentrant storage. */ otherwise the return value shares the mprec reentrant storage. */
# ifdef _NO_LONGDBL
static char * static char *
_DEFUN(cvt, (data, value, ndigits, flags, sign, decpt, ch, length, buf), cvt(struct _reent *data, _PRINTF_FLOAT_TYPE value, int ndigits, int flags,
struct _reent *data _AND char *sign, int *decpt, int ch, int *length, char *buf)
double value _AND
int ndigits _AND
int flags _AND
char *sign _AND
int *decpt _AND
int ch _AND
int *length _AND
char *buf)
# else
static char *
_DEFUN(cvt, (data, value, ndigits, flags, sign, decpt, ch, length, buf),
struct _reent *data _AND
_LONG_DOUBLE value _AND
int ndigits _AND
int flags _AND
char *sign _AND
int *decpt _AND
int ch _AND
int *length _AND
char *buf)
# endif
{ {
int mode, dsgn; int mode, dsgn;
char *digits, *bp, *rve; char *digits, *bp, *rve;
@ -1444,13 +1428,10 @@ _DEFUN(cvt, (data, value, ndigits, flags, sign, decpt, ch, length, buf),
} }
static int static int
_DEFUN(exponent, (p0, exp, fmtch), exponent(char *p0, int exp, int fmtch)
char *p0 _AND
int exp _AND
int fmtch)
{ {
register char *p, *t; register char *p, *t;
char expbuf[10]; char expbuf[MAXEXPLEN];
# ifdef _WANT_IO_C99_FORMATS # ifdef _WANT_IO_C99_FORMATS
int isa = fmtch == 'a' || fmtch == 'A'; int isa = fmtch == 'a' || fmtch == 'A';
# else # else
@ -1465,13 +1446,13 @@ _DEFUN(exponent, (p0, exp, fmtch),
} }
else else
*p++ = '+'; *p++ = '+';
t = expbuf + 10; t = expbuf + MAXEXPLEN;
if (exp > 9) { if (exp > 9) {
do { do {
*--t = to_char (exp % 10); *--t = to_char (exp % 10);
} while ((exp /= 10) > 9); } while ((exp /= 10) > 9);
*--t = to_char (exp); *--t = to_char (exp);
for (; t < expbuf + 10; *p++ = *t++); for (; t < expbuf + MAXEXPLEN; *p++ = *t++);
} }
else { else {
if (!isa) if (!isa)