(___printf_fp): Minor optimization.
[kopensolaris-gnu/glibc.git] / stdio-common / printf_fp.c
index 66a6084..32df06a 100644 (file)
@@ -1,5 +1,6 @@
 /* Floating point output for `printf'.
-   Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1995-2003, 2006, 2007 Free Software Foundation, Inc.
+
    This file is part of the GNU C Library.
    Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
 
 /* The gmp headers need some configuration frobs.  */
 #define HAVE_ALLOCA 1
 
-#ifdef USE_IN_LIBIO
-#  include <libioP.h>
-#else
-#  include <stdio.h>
-#endif
+#include <libioP.h>
 #include <alloca.h>
 #include <ctype.h>
 #include <float.h>
 #include <stdlib.h>
 #include <wchar.h>
 
+#ifdef COMPILE_WPRINTF
+# define CHAR_T        wchar_t
+#else
+# define CHAR_T        char
+#endif
+
+#include "_i18n_number.h"
+
 #ifndef NDEBUG
 # define NDEBUG                        /* Undefine this for debugging assertions.  */
 #endif
 
 /* This defines make it possible to use the same code for GNU C library and
    the GNU I/O library.         */
-#ifdef USE_IN_LIBIO
-# define PUT(f, s, n) _IO_sputn (f, s, n)
-# define PAD(f, c, n) (wide ? _IO_wpadn (f, c, n) : INTUSE(_IO_padn) (f, c, n))
+#define PUT(f, s, n) _IO_sputn (f, s, n)
+#define PAD(f, c, n) (wide ? _IO_wpadn (f, c, n) : INTUSE(_IO_padn) (f, c, n))
 /* We use this file GNU C library and GNU I/O library. So make
    names equal.         */
-# undef putc
-# define putc(c, f) (wide \
-                     ? (int)_IO_putwc_unlocked (c, f) : _IO_putc_unlocked (c, f))
-# define size_t     _IO_size_t
-# define FILE       _IO_FILE
-#else  /* ! USE_IN_LIBIO */
-# define PUT(f, s, n) fwrite (s, 1, n, f)
-# define PAD(f, c, n) __printf_pad (f, c, n)
-ssize_t __printf_pad __P ((FILE *, char pad, int n)); /* In vfprintf.c.  */
-#endif /* USE_IN_LIBIO */
+#undef putc
+#define putc(c, f) (wide \
+                   ? (int)_IO_putwc_unlocked (c, f) : _IO_putc_unlocked (c, f))
+#define size_t     _IO_size_t
+#define FILE        _IO_FILE
 \f
 /* Macros for doing the actual output.  */
 
@@ -73,7 +72,11 @@ ssize_t __printf_pad __P ((FILE *, char pad, int n)); /* In vfprintf.c.  */
     {                                                                        \
       register const int outc = (ch);                                        \
       if (putc (outc, fp) == EOF)                                            \
-       return -1;                                                            \
+       {                                                                     \
+         if (buffer_malloced)                                                \
+           free (wbuffer);                                                   \
+         return -1;                                                          \
+       }                                                                     \
       ++done;                                                                \
     } while (0)
 
@@ -84,7 +87,11 @@ ssize_t __printf_pad __P ((FILE *, char pad, int n)); /* In vfprintf.c.  */
       if (len > 20)                                                          \
        {                                                                     \
          if (PUT (fp, wide ? (const char *) wptr : ptr, outlen) != outlen)   \
-           return -1;                                                        \
+           {                                                                 \
+             if (buffer_malloced)                                            \
+               free (wbuffer);                                               \
+             return -1;                                                      \
+           }                                                                 \
          ptr += outlen;                                                      \
          done += outlen;                                                     \
        }                                                                     \
@@ -103,7 +110,11 @@ ssize_t __printf_pad __P ((FILE *, char pad, int n)); /* In vfprintf.c.  */
   do                                                                         \
     {                                                                        \
       if (PAD (fp, ch, len) != len)                                          \
-       return -1;                                                            \
+       {                                                                     \
+         if (buffer_malloced)                                                \
+           free (wbuffer);                                                   \
+         return -1;                                                          \
+       }                                                                     \
       done += len;                                                           \
     }                                                                        \
   while (0)
@@ -120,7 +131,8 @@ ssize_t __printf_pad __P ((FILE *, char pad, int n)); /* In vfprintf.c.  */
 #define MPN_GE(u,v) \
   (u##size > v##size || (u##size == v##size && __mpn_cmp (u, v, u##size) >= 0))
 
-extern int __isinfl (long double), __isnanl (long double);
+extern int __isinfl_internal (long double) attribute_hidden;
+extern int __isnanl_internal (long double) attribute_hidden;
 
 extern mp_size_t __mpn_extract_double (mp_ptr res_ptr, mp_size_t size,
                                       int *expt, int *is_neg,
@@ -139,9 +151,9 @@ static wchar_t *group_number (wchar_t *buf, wchar_t *bufend,
 
 
 int
-__printf_fp (FILE *fp,
-            const struct printf_info *info,
-            const void *const *args)
+___printf_fp (FILE *fp,
+             const struct printf_info *info,
+             const void *const *args)
 {
   /* The floating-point value to output.  */
   union
@@ -200,6 +212,11 @@ __printf_fp (FILE *fp,
   /* Nonzero if this is output on a wide character stream.  */
   int wide = info->wide;
 
+  /* Buffer in which we produce the output.  */
+  wchar_t *wbuffer = NULL;
+  /* Flag whether wbuffer is malloc'ed or not.  */
+  int buffer_malloced = 0;
+
   auto wchar_t hack_digit (void);
 
   wchar_t hack_digit (void)
@@ -211,8 +228,7 @@ __printf_fp (FILE *fp,
       else if (scalesize == 0)
        {
          hi = frac[fracsize - 1];
-         cy = __mpn_mul_1 (frac, frac, fracsize - 1, 10);
-         frac[fracsize - 1] = cy;
+         frac[fracsize - 1] = __mpn_mul_1 (frac, frac, fracsize - 1, 10);
        }
       else
        {
@@ -236,9 +252,9 @@ __printf_fp (FILE *fp,
                }
            }
 
-         cy = __mpn_mul_1 (frac, frac, fracsize, 10);
-         if (cy != 0)
-           frac[fracsize++] = cy;
+         mp_limb_t _cy = __mpn_mul_1 (frac, frac, fracsize, 10);
+         if (_cy != 0)
+           frac[fracsize++] = _cy;
        }
 
       return L'0' + hi;
@@ -363,6 +379,7 @@ __printf_fp (FILE *fp,
       /* Check for special values: not a number or infinity.  */
       if (__isnan (fpnum.dbl))
        {
+         is_neg = 0;
          if (isupper (info->spec))
            {
              special = "NAN";
@@ -373,10 +390,10 @@ __printf_fp (FILE *fp,
              special = "nan";
              wspecial = L"nan";
            }
-         is_neg = 0;
        }
       else if (__isinf (fpnum.dbl))
        {
+         is_neg = fpnum.dbl < 0;
          if (isupper (info->spec))
            {
              special = "INF";
@@ -387,7 +404,6 @@ __printf_fp (FILE *fp,
              special = "inf";
              wspecial = L"inf";
            }
-         is_neg = fpnum.dbl < 0;
        }
       else
        {
@@ -432,7 +448,9 @@ __printf_fp (FILE *fp,
      would be really big it could lead to memory problems.  */
   {
     mp_size_t bignum_size = ((ABS (exponent) + BITS_PER_MP_LIMB - 1)
-                            / BITS_PER_MP_LIMB + 4) * sizeof (mp_limb_t);
+                            / BITS_PER_MP_LIMB
+                            + (LDBL_MANT_DIG / BITS_PER_MP_LIMB > 2 ? 8 : 4))
+                           * sizeof (mp_limb_t);
     frac = (mp_limb_t *) alloca (bignum_size);
     tmp = (mp_limb_t *) alloca (bignum_size);
     scale = (mp_limb_t *) alloca (bignum_size);
@@ -493,6 +511,9 @@ __printf_fp (FILE *fp,
                              &__tens[powers->arrayoff],
                              tmpsize * sizeof (mp_limb_t));
                      MPN_ZERO (tmp, _FPIO_CONST_SHIFT);
+                     /* Adjust exponent, as scaleexpo will be this much
+                        bigger too.  */
+                     exponent += _FPIO_CONST_SHIFT * BITS_PER_MP_LIMB;
                    }
                  else
 #endif
@@ -786,17 +807,18 @@ __printf_fp (FILE *fp,
 
   {
     int width = info->width;
-    wchar_t *wbuffer, *wstartp, *wcp;
-    int buffer_malloced;
+    wchar_t *wstartp, *wcp;
     int chars_needed;
     int expscale;
     int intdig_max, intdig_no = 0;
-    int fracdig_min, fracdig_max, fracdig_no = 0;
+    int fracdig_min;
+    int fracdig_max;
     int dig_max;
     int significant;
     int ngroups = 0;
+    char spec = _tolower (info->spec);
 
-    if (_tolower (info->spec) == 'e')
+    if (spec == 'e')
       {
        type = info->spec;
        intdig_max = 1;
@@ -806,10 +828,12 @@ __printf_fp (FILE *fp,
        dig_max = INT_MAX;              /* Unlimited.  */
        significant = 1;                /* Does not matter here.  */
       }
-    else if (info->spec == 'f')
+    else if (spec == 'f')
       {
        type = 'f';
        fracdig_min = fracdig_max = info->prec < 0 ? 6 : info->prec;
+       dig_max = INT_MAX;              /* Unlimited.  */
+       significant = 1;                /* Does not matter here.  */
        if (expsign == 0)
          {
            intdig_max = exponent + 1;
@@ -821,8 +845,6 @@ __printf_fp (FILE *fp,
            intdig_max = 1;
            chars_needed = 1 + 1 + fracdig_max;
          }
-       dig_max = INT_MAX;              /* Unlimited.  */
-       significant = 1;                /* Does not matter here.  */
       }
     else
       {
@@ -866,8 +888,8 @@ __printf_fp (FILE *fp,
        it is possible that we need two more characters in front of all the
        other output.  If the amount of memory we have to allocate is too
        large use `malloc' instead of `alloca'.  */
-    buffer_malloced = chars_needed > 5000;
-    if (buffer_malloced)
+    buffer_malloced = ! __libc_use_alloca (chars_needed * 2 * sizeof (wchar_t));
+    if (__builtin_expect (buffer_malloced, 0))
       {
        wbuffer = (wchar_t *) malloc ((2 + chars_needed) * sizeof (wchar_t));
        if (wbuffer == NULL)
@@ -903,12 +925,13 @@ __printf_fp (FILE *fp,
       }
 
     /* Generate the needed number of fractional digits.         */
+    int fracdig_no = 0;
     while (fracdig_no < fracdig_min
           || (fracdig_no < fracdig_max && (fracsize > 1 || frac[0] != 0)))
       {
        ++fracdig_no;
        *wcp = hack_digit ();
-       if (*wcp != L'0')
+       if (*wcp++ != L'0')
          significant = 1;
        else if (significant == 0)
          {
@@ -916,7 +939,6 @@ __printf_fp (FILE *fp,
            if (fracdig_min > 0)
              ++fracdig_min;
          }
-       ++wcp;
       }
 
     /* Do rounding.  */
@@ -953,7 +975,7 @@ __printf_fp (FILE *fp,
            /* Process fractional digits.  Terminate if not rounded or
               radix character is reached.  */
            while (*--wtp != decimalwc && *wtp == L'9')
-             *wtp = '0';
+             *wtp = L'0';
            if (*wtp != decimalwc)
              /* Round up.  */
              (*wtp)++;
@@ -1101,13 +1123,16 @@ __printf_fp (FILE *fp,
          else
            thousands_sep_len = strlen (thousands_sep);
 
-         if (buffer_malloced)
+         if (__builtin_expect (buffer_malloced, 0))
            {
              buffer = (char *) malloc (2 + chars_needed + decimal_len
                                        + ngroups * thousands_sep_len);
              if (buffer == NULL)
-               /* Signal an error to the caller.  */
-               return -1;
+               {
+                 /* Signal an error to the caller.  */
+                 free (wbuffer);
+                 return -1;
+               }
            }
          else
            buffer = (char *) alloca (2 + chars_needed + decimal_len
@@ -1127,10 +1152,19 @@ __printf_fp (FILE *fp,
        }
 
       tmpptr = buffer;
+      if (__builtin_expect (info->i18n, 0))
+        {
+#ifdef COMPILE_WPRINTF
+         wstartp = _i18n_number_rewrite (wstartp, wcp);
+#else
+         tmpptr = _i18n_number_rewrite (tmpptr, cp);
+#endif
+        }
+
       PRINT (tmpptr, wstartp, wide ? wcp - wstartp : cp - tmpptr);
 
       /* Free the memory if necessary.  */
-      if (buffer_malloced)
+      if (__builtin_expect (buffer_malloced, 0))
        {
          free (buffer);
          free (wbuffer);
@@ -1142,6 +1176,8 @@ __printf_fp (FILE *fp,
   }
   return done;
 }
+ldbl_hidden_def (___printf_fp, __printf_fp)
+ldbl_strong_alias (___printf_fp, __printf_fp)
 \f
 /* Return the number of extra grouping characters that will be inserted
    into a number with INTDIG_MAX integer digits.  */