OSDN Git Service

Reduce stack size of *printf.
authorericb <ericb>
Mon, 14 May 2007 19:42:47 +0000 (19:42 +0000)
committerericb <ericb>
Mon, 14 May 2007 19:42:47 +0000 (19:42 +0000)
* 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.

newlib/ChangeLog
newlib/libc/stdio/vfprintf.c

index 6986e6e..d41cba3 100644 (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>
 
        Minimize printf/scanf size on platforms that don't need C99.
index 6175f0e..5305840 100644 (file)
@@ -224,43 +224,66 @@ _DEFUN(__sbprintf, (rptr, fp, fmt, ap),
 
 
 #ifdef FLOATING_POINT
-#include <locale.h>
-#include <math.h>
-#include "floatio.h"
-
-#if ((MAXEXP+MAXFRACT+1) > MB_LEN_MAX)
-#  define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
-#else 
-#  define BUF MB_LEN_MAX
-#endif
+# include <locale.h>
+# include <math.h>
 
-#define        DEFPREC         6
+/* For %La, an exponent of 15 bits occupies the exponent character, a
+   sign, and up to 5 digits.  */
+# define MAXEXPLEN             7
+# 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 *));
-#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 */
 
+/* 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
-#define quad_t long long
-#define u_quad_t unsigned long long
+# define quad_t long long
+# define u_quad_t unsigned long long
 #else
-#define quad_t long
-#define u_quad_t unsigned long
+# define quad_t long
+# define u_quad_t unsigned long
 #endif
 
 typedef quad_t * quad_ptr_t;
@@ -378,19 +401,13 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap),
 #ifdef FLOATING_POINT
        char *decimal_point = _localeconv_r (data)->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
+       union { int i; _PRINTF_FLOAT_TYPE fp; } _double_ = {0};
+# define _fpvalue (_double_.fp)
        int expt;               /* integer value of exponent */
        int expsize = 0;        /* character count for expstr */
        int ndig = 0;           /* actual number of digits returned by cvt */
-       char expstr[7];         /* buffer for exponent string */
-#endif
+       char expstr[MAXEXPLEN]; /* buffer for exponent string */
+#endif /* FLOATING_POINT */
        u_quad_t _uquad;        /* integer arguments %[diouxX] */
        enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
        int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
@@ -400,7 +417,7 @@ _DEFUN(_VFPRINTF_R, (data, fp, fmt0, ap),
 #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 buf[BUF];          /* space for %c, %S, %[diouxX], %[aA] */
        char ox[2];             /* space for 0x hex-prefix */
 #ifdef _MB_CAPABLE
        wchar_t wc;
@@ -875,8 +892,8 @@ reswitch:   switch (ch) {
                        }
 
                        /* do this before tricky precision changes */
-                       tmp = _ldcheck (&_fpvalue);
-                       if (tmp == 2) {
+                       expt = _ldcheck (&_fpvalue);
+                       if (expt == 2) {
                                if (_fpvalue < 0)
                                        sign = '-';
                                if (ch <= 'G') /* 'A', 'E', 'F', or 'G' */
@@ -887,7 +904,7 @@ reswitch:   switch (ch) {
                                flags &= ~ZEROPAD;
                                break;
                        }
-                       if (tmp == 1) {
+                       if (expt == 1) {
                                if (ch <= 'G') /* 'A', 'E', 'F', or 'G' */
                                        cp = "NAN";
                                else
@@ -1030,8 +1047,8 @@ reswitch: switch (ch) {
                                        while (1) {
                                                if (wcp[m] == L'\0')
                                                        break;
-                                               if ((n = (int)_wcrtomb_r (data, 
-                                                     buf, wcp[m], &ps)) == -1) {
+                                               if ((n = (int)_wcrtomb_r (data,
+                                                    buf, wcp[m], &ps)) == -1) {
                                                        fp->_flags |= __SERR;
                                                        goto error;
                                                }
@@ -1044,31 +1061,35 @@ reswitch:       switch (ch) {
                                        }
                                }
                                else {
-                                       if ((size = (int)_wcsrtombs_r (data, 
-                                                   NULL, &wcp, 0, &ps)) == -1) {
+                                       if ((size = (int)_wcsrtombs_r (data,
+                                                  NULL, &wcp, 0, &ps)) == -1) {
                                                fp->_flags |= __SERR;
                                                goto error;
                                        }
                                        wcp = (_CONST wchar_t *)cp;
                                }
+
                                if (size == 0)
                                        break;
-                               if ((malloc_buf = 
-                                   (char *)_malloc_r (data, size + 1)) == NULL) {
-                                       fp->_flags |= __SERR;
-                                       goto error;
-                               }
-                             
+
+                               if (size >= BUF) {
+                                       if ((malloc_buf =
+                                            (char *)_malloc_r (data, size + 1))
+                                           == NULL) {
+                                               fp->_flags |= __SERR;
+                                               goto error;
+                                       }
+                                       cp = malloc_buf;
+                               } else
+                                       cp = buf;
+
                                /* Convert widechar string to multibyte string. */
                                memset ((_PTR)&ps, '\0', sizeof (mbstate_t));
-                               if (_wcsrtombs_r (data, malloc_buf, 
-                                                 &wcp, size, &ps) != size) {
+                               if (_wcsrtombs_r (data, malloc_buf,
+                                                &wcp, size, &ps) != size) {
                                        fp->_flags |= __SERR;
                                        goto error;
                                }
-                               cp = malloc_buf;
                                cp[size] = '\0';
                        }
 #endif /* _MB_CAPABLE */
@@ -1254,11 +1275,11 @@ number:                 if ((dprec = prec) >= 0)
                                        PRINT (cp, ndig);
                                        PAD (expt - ndig, zeroes);
                                        if (flags & ALT)
-                                               PRINT (".", 1);
+                                               PRINT (decimal_point, 1);
                                } else {
                                        PRINT (cp, expt);
                                        cp += expt;
-                                       PRINT (".", 1);
+                                       PRINT (decimal_point, 1);
                                        PRINT (cp, ndig - expt);
                                }
                        } else {        /* 'a', 'A', 'e', or 'E' */
@@ -1305,21 +1326,6 @@ error:
 
 #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
    with no decimal point, using NDIGITS precision and FLAGS as guides
    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
    [aAeEfFgG]; if it is [aA], then the return string lives in BUF,
    otherwise the return value shares the mprec reentrant storage.  */
-# ifdef _NO_LONGDBL
-static char *
-_DEFUN(cvt, (data, value, ndigits, flags, sign, decpt, ch, length, buf),
-       struct _reent *data _AND
-       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
+cvt(struct _reent *data, _PRINTF_FLOAT_TYPE value, int ndigits, int flags,
+    char *sign, int *decpt, int ch, int *length, char *buf)
 {
        int mode, dsgn;
        char *digits, *bp, *rve;
@@ -1444,13 +1428,10 @@ _DEFUN(cvt, (data, value, ndigits, flags, sign, decpt, ch, length, buf),
 }
 
 static int
-_DEFUN(exponent, (p0, exp, fmtch),
-       char *p0 _AND
-       int exp  _AND
-       int fmtch)
+exponent(char *p0, int exp, int fmtch)
 {
        register char *p, *t;
-       char expbuf[10];
+       char expbuf[MAXEXPLEN];
 # ifdef _WANT_IO_C99_FORMATS
        int isa = fmtch == 'a' || fmtch == 'A';
 # else
@@ -1465,13 +1446,13 @@ _DEFUN(exponent, (p0, exp, fmtch),
        }
        else
                *p++ = '+';
-       t = expbuf + 10;
+       t = expbuf + MAXEXPLEN;
        if (exp > 9) {
                do {
                        *--t = to_char (exp % 10);
                } while ((exp /= 10) > 9);
                *--t = to_char (exp);
-               for (; t < expbuf + 10; *p++ = *t++);
+               for (; t < expbuf + MAXEXPLEN; *p++ = *t++);
        }
        else {
                if (!isa)