Bash-4.3 distribution sources and documentation
[platform/upstream/bash.git] / lib / sh / snprintf.c
index 7669576..87ca217 100644 (file)
@@ -1,3 +1,5 @@
+/* snprintf - formatted output to strings, with bounds checking and allocation */
+
 /*
  build a test version with
    gcc -g -DDRIVER -I../.. -I../../include -o test-snprintf snprintf.c fmtu*long.o
@@ -7,23 +9,24 @@
    Unix snprintf implementation.
    derived from inetutils/libinetutils/snprintf.c Version 1.1
 
-   Copyright (C) 2001 Free Software Foundation, Inc.
+   Copyright (C) 2001,2006,2010,2012 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
 
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   Bash is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
+
+   Bash is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General License for more details.
-   
-   You should have received a copy of the GNU General License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
    
-   Revision History:
+   Original (pre-bash) Revision History:
 
    1.1:
       *  added changes from Miles Bader
 
 /*
  * Currently doesn't handle (and bash/readline doesn't use):
- *     *M$ width, precision specifications
- *     %N$ numbered argument conversions
- *     inf, nan floating values imperfect (if isinf(), isnan() not in libc)
- *     support for `F' is imperfect, since underlying printf may not handle it
+ *     * *M$ width, precision specifications
+ *     %N$ numbered argument conversions
+ *     * support for `F' is imperfect with ldfallback(), since underlying
+ *       printf may not handle it -- should ideally have another autoconf test
  */
 
 #define FLOATING_POINT
 #  include <config.h>
 #endif
 
+/* GCC 4.2 on Snow Leopard doesn't like the snprintf prototype */
+#if defined(DEBUG) && !defined (MACOSX)
+#  undef HAVE_SNPRINTF
+#  undef HAVE_ASPRINTF
+
+#  define HAVE_SNPRINTF 0
+#  define HAVE_ASPRINTF 0
+#endif
+
 #if defined(DRIVER) && !defined(HAVE_CONFIG_H)
 #define HAVE_LONG_LONG
 #define HAVE_LONG_DOUBLE
@@ -64,6 +76,7 @@
 #define HAVE_PRINTF_A_FORMAT
 #endif
 #define HAVE_ISINF_IN_LIBC
+#define HAVE_ISNAN_IN_LIBC
 #define PREFER_STDARG
 #define HAVE_STRINGIZE
 #define HAVE_LIMITS_H
@@ -72,7 +85,7 @@
 #define intmax_t long
 #endif
 
-#if !defined (HAVE_SNPRINTF) || !defined (HAVE_ASPRINTF)
+#if !HAVE_SNPRINTF || !HAVE_ASPRINTF
 
 #include <bashtypes.h>
 
@@ -289,6 +302,32 @@ static void dfallback __P((struct DATA *, const char *, const char *, double));
 
 static char *groupnum __P((char *));
 
+#if defined (HAVE_LONG_DOUBLE)
+#  define LONGDOUBLE long double
+#else
+#  define LONGDOUBLE double
+#endif
+
+#ifndef isnan
+  static inline int isnan_f  (float       x) { return x != x; }
+  static inline int isnan_d  (double      x) { return x != x; }
+  static inline int isnan_ld (LONGDOUBLE  x) { return x != x; }
+  # define isnan(x) \
+      (sizeof (x) == sizeof (LONGDOUBLE) ? isnan_ld (x) \
+       : sizeof (x) == sizeof (double) ? isnan_d (x) \
+       : isnan_f (x))
+#endif
+  
+#ifndef isinf
+  static inline int isinf_f  (float       x) { return !isnan (x) && isnan (x - x); }
+  static inline int isinf_d  (double      x) { return !isnan (x) && isnan (x - x); }
+  static inline int isinf_ld (LONGDOUBLE  x) { return !isnan (x) && isnan (x - x); }
+  # define isinf(x) \
+      (sizeof (x) == sizeof (LONGDOUBLE) ? isinf_ld (x) \
+       : sizeof (x) == sizeof (double) ? isinf_d (x) \
+       : isinf_f (x))
+#endif
+
 #ifdef DRIVER
 static void memory_error_and_abort ();
 static void *xmalloc __P((size_t));
@@ -350,7 +389,7 @@ static void xfree __P((void *));
        while (0)
 
 #define PUT_PLUS(d, p, zero) \
-           if ((d) > zero && (p)->justify == RIGHT) \
+           if (((p)->flags & PF_PLUS) && (d) > zero) \
              PUT_CHAR('+', p)
 
 #define PUT_SPACE(d, p, zero) \
@@ -369,14 +408,37 @@ static void xfree __P((void *));
              for (; (p)->width > 0; (p)->width--) \
                 PUT_CHAR((p)->pad, p)
 
+/* pad with zeros from decimal precision */
+#define PAD_ZERO(p) \
+       if ((p)->precision > 0) \
+         for (; (p)->precision > 0; (p)->precision--) \
+           PUT_CHAR('0', p)
+
 /* if width and prec. in the args */
 #define STAR_ARGS(p) \
+       do { \
            if ((p)->flags & PF_STAR_W) \
-             (p)->width = GETARG (int); \
+             { \
+               (p)->width = GETARG (int); \
+               if ((p)->width < 0) \
+                 { \
+                   (p)->flags |= PF_LADJUST; \
+                   (p)->justify = LEFT; \
+                   (p)->width = -(p)->width; \
+                 } \
+             } \
            if ((p)->flags & PF_STAR_P) \
-             (p)->precision = GETARG (int)
+             { \
+               (p)->precision = GETARG (int); \
+               if ((p)->precision < 0) \
+                 { \
+                   (p)->flags &= ~PF_STAR_P; \
+                   (p)->precision = NOT_FOUND; \
+                 } \
+             } \
+       } while (0)
 
-#if defined (HAVE_LOCALE_H)
+#if defined (HAVE_LOCALE_H) && defined (HAVE_LOCALECONV)
 #  define GETLOCALEDATA(d, t, g) \
       do \
        { \
@@ -387,9 +449,9 @@ static void xfree __P((void *));
          if (lv) \
            { \
              if (lv->decimal_point && lv->decimal_point[0]) \
-               (d) = lv->decimal_point[0]; \
+               (d) = lv->decimal_point[0]; \
              if (lv->thousands_sep && lv->thousands_sep[0]) \
-               (t) = lv->thousands_sep[0]; \
+               (t) = lv->thousands_sep[0]; \
              (g) = lv->grouping ? lv->grouping : ""; \
              if (*(g) == '\0' || *(g) == CHAR_MAX || (t) == -1) (g) = 0; \
            } \
@@ -446,6 +508,8 @@ pow_10(n)
          10^x ~= r
  * log_10(200) = 2;
  * log_10(250) = 2;
+ *
+ * NOTE: do not call this with r == 0 -- an infinite loop results.
  */
 static int
 log_10(r)
@@ -528,7 +592,7 @@ integral(real, ip)
 /* 
  * return an ascii representation of the integral part of the number
  * and set fract to be an ascii representation of the fraction part
- * the container for the fraction and the integral part or staticly
+ * the container for the fraction and the integral part or statically
  * declare with fix size 
  */
 static char *
@@ -540,10 +604,9 @@ numtoa(number, base, precision, fract)
   register int i, j;
   double ip, fp; /* integer and fraction part */
   double fraction;
-  int digits = MAX_INT - 1;
+  int digits, sign;
   static char integral_part[MAX_INT];
   static char fraction_part[MAX_FRACT];
-  double sign;
   int ch;
 
   /* taking care of the obvious case: 0.0 */
@@ -551,15 +614,22 @@ numtoa(number, base, precision, fract)
     { 
       integral_part[0] = '0';
       integral_part[1] = '\0';
-      fraction_part[0] = '0';
-      fraction_part[1] = '\0';
+      /* The fractional part has to take the precision into account */
+      for (ch = 0; ch < precision-1; ch++)
+       fraction_part[ch] = '0';
+      fraction_part[ch] = '0';
+      fraction_part[ch+1] = '\0';
       if (fract)
        *fract = fraction_part;
       return integral_part;
     }
 
+  /* -0 is tricky */
+  sign = (number == -0.) ? '-' : ((number < 0.) ? '-' : '+');
+  digits = MAX_INT - 1;
+
   /* for negative numbers */
-  if ((sign = number) < 0.)
+  if (sign == '-')
     {
       number = -number;
       digits--; /* sign consume one digit */
@@ -594,7 +664,7 @@ numtoa(number, base, precision, fract)
       integral_part[i] = '9';
 
   /* put the sign ? */
-  if (sign < 0.)
+  if (sign == '-')
     integral_part[i++] = '-';
 
   integral_part[i] = '\0';
@@ -633,8 +703,17 @@ number(p, d, base)
   long sd;
   int flags;
 
+  /* An explicit precision turns off the zero-padding flag and sets the
+     pad character back to space. */
+  if ((p->flags & PF_ZEROPAD) && p->precision >= 0 && (p->flags & PF_DOT))
+    {
+      p->flags &= ~PF_ZEROPAD;
+      p->pad = ' ';
+    }
+
   sd = d;      /* signed for ' ' padding in base 10 */
-  flags = (*p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0;
+  flags = 0;
+  flags = (*p->pf == 'x' || *p->pf == 'X' || *p->pf == 'o' || *p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0;
   if (*p->pf == 'X')
     flags |= FL_HEXUPPER;
 
@@ -644,12 +723,19 @@ number(p, d, base)
     {
       GETLOCALEDATA(decpoint, thoussep, grouping);
       if (grouping && (t = groupnum (tmp)))
-        tmp = t;
+       tmp = t;
     }
 
-  p->width -= strlen(tmp);
+  /* need to add one for any `+', but we only add one in base 10 */
+  p->width -= strlen(tmp) + (base == 10 && d > 0 && (p->flags & PF_PLUS));
   PAD_RIGHT(p);
 
+  if ((p->flags & PF_DOT) && p->precision > 0)
+    {
+      p->precision -= strlen(tmp);
+      PAD_ZERO(p);
+    }
+
   switch (base)
     {
     case 10:
@@ -693,8 +779,16 @@ lnumber(p, d, base)
   long long sd;
   int flags;
 
+  /* An explicit precision turns off the zero-padding flag and sets the
+     pad character back to space. */
+  if ((p->flags & PF_ZEROPAD) && p->precision >= 0 && (p->flags & PF_DOT))
+    {
+      p->flags &= ~PF_ZEROPAD;
+      p->pad = ' ';
+    }
+
   sd = d;      /* signed for ' ' padding in base 10 */
-  flags = (*p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0;
+  flags = (*p->pf == 'x' || *p->pf == 'X' || *p->pf == 'o' || *p->pf == 'u' || *p->pf == 'U') ? FL_UNSIGNED : 0;
   if (*p->pf == 'X')
     flags |= FL_HEXUPPER;
 
@@ -704,12 +798,19 @@ lnumber(p, d, base)
     {
       GETLOCALEDATA(decpoint, thoussep, grouping);
       if (grouping && (t = groupnum (tmp)))
-        tmp = t;
+       tmp = t;
     }
 
-  p->width -= strlen(tmp);
+  /* need to add one for any `+', but we only add one in base 10 */
+  p->width -= strlen(tmp) + (base == 10 && d > 0 && (p->flags & PF_PLUS));
   PAD_RIGHT(p);
 
+  if ((p->flags & PF_DOT) && p->precision > 0)
+    {
+      p->precision -= strlen(tmp);
+      PAD_ZERO(p);
+    }
+
   switch (base)
     {
     case 10:
@@ -760,6 +861,7 @@ pointer(p, d)
       PUT_CHAR(*tmp, p);
       tmp++;
     }
+
   PAD_LEFT(p);
 }
 
@@ -804,11 +906,11 @@ wstrings(p, tmp)
     {
       len = wcsrtombs (NULL, &ws, 0, &mbs);
       if (len != (size_t)-1)
-        {
+       {
          memset (&mbs, '\0', sizeof (mbstate_t));
          os = (char *)xmalloc (len + 1);
          (void)wcsrtombs (os, &ws, len + 1, &mbs);
-        }
+       }
     }
   if (len == (size_t)-1)
     {
@@ -848,30 +950,6 @@ wchars (p, wc)
 
 #ifdef FLOATING_POINT
 
-#ifndef HAVE_ISINF_IN_LIBC
-/* Half-assed versions, since we don't want to link with libm. */
-static int
-isinf(d)
-     double d;
-{
-#ifdef DBL_MAX
-  if (d < DBL_MIN)
-    return -1;
-  else if (d > DBL_MAX)
-    return 1;
-  else
-#endif
-    return 0;
-}
-
-static int
-isnan(d)
-     double d;
-{
-  return 0;
-}
-#endif
-
 /* Check for [+-]infinity and NaN.  If MODE == 1, we check for Infinity, else
    (mode == 2) we check for NaN.  This does the necessary printing.  Returns
    1 if Inf or Nan, 0 if not. */
@@ -914,7 +992,7 @@ floating(p, d)
   char *tmp, *tmp2, *t;
   int i;
 
-  if (chkinfnan(p, d, 1) || chkinfnan(p, d, 2))
+  if (d != 0 && (chkinfnan(p, d, 1) || chkinfnan(p, d, 2)))
     return;    /* already printed nan or inf */
 
   GETLOCALEDATA(decpoint, thoussep, grouping);
@@ -925,18 +1003,44 @@ floating(p, d)
   if ((p->flags & PF_THOUSANDS) && grouping && (t = groupnum (tmp)))
     tmp = t;
 
+  if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0)
+    {
+      /* smash the trailing zeros unless altform */
+      for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
+       tmp2[i] = '\0'; 
+      if (tmp2[0] == '\0')
+       p->precision = 0;
+    }
+
   /* calculate the padding. 1 for the dot */
   p->width = p->width -
+           /* XXX - should this be d>0. && (p->flags & PF_PLUS) ? */
+#if 0
            ((d > 0. && p->justify == RIGHT) ? 1:0) -
+#else
+           ((d > 0. && (p->flags & PF_PLUS)) ? 1:0) -
+#endif
            ((p->flags & PF_SPACE) ? 1:0) -
-           strlen(tmp) - p->precision - 1;
-  PAD_RIGHT(p);  
-  PUT_PLUS(d, p, 0.);
+           strlen(tmp) - p->precision -
+           ((p->precision != 0 || (p->flags & PF_ALTFORM)) ? 1 : 0);   /* radix char */
+
+  if (p->pad == ' ')
+    {
+      PAD_RIGHT(p);
+      PUT_PLUS(d, p, 0.);
+    }
+  else
+    {
+      if (*tmp == '-')
+       PUT_CHAR(*tmp++, p);
+      PUT_PLUS(d, p, 0.);
+      PAD_RIGHT(p);
+    }
   PUT_SPACE(d, p, 0.);
 
   while (*tmp)
-    { /* the integral */
-      PUT_CHAR(*tmp, p);
+    {
+      PUT_CHAR(*tmp, p);       /* the integral */
       tmp++;
     }
   FREE (t);
@@ -944,11 +1048,6 @@ floating(p, d)
   if (p->precision != 0 || (p->flags & PF_ALTFORM))
     PUT_CHAR(decpoint, p);  /* put the '.' */
 
-  if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0)
-    /* smash the trailing zeros unless altform */
-    for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
-      tmp2[i] = '\0'; 
-
   for (; *tmp2; tmp2++)
     PUT_CHAR(*tmp2, p); /* the fraction */
   
@@ -964,25 +1063,46 @@ exponent(p, d)
   char *tmp, *tmp2;
   int j, i;
 
-  if (chkinfnan(p, d, 1) || chkinfnan(p, d, 2))
+  if (d != 0 && (chkinfnan(p, d, 1) || chkinfnan(p, d, 2)))
     return;    /* already printed nan or inf */
 
   GETLOCALEDATA(decpoint, thoussep, grouping);
   DEF_PREC(p);
-  j = log_10(d);
-  d = d / pow_10(j);  /* get the Mantissa */
-  d = ROUND(d, p);               
+  if (d == 0.)
+    j = 0;
+  else
+    {
+      j = log_10(d);
+      d = d / pow_10(j);  /* get the Mantissa */
+      d = ROUND(d, p);           
+    }
   tmp = dtoa(d, p->precision, &tmp2);
 
   /* 1 for unit, 1 for the '.', 1 for 'e|E',
-   * 1 for '+|-', 2 for 'exp' */
+   * 1 for '+|-', 2 for 'exp'  (but no `.' if precision == 0 */
   /* calculate how much padding need */
   p->width = p->width - 
+           /* XXX - should this be d>0. && (p->flags & PF_PLUS) ? */
+#if 0
             ((d > 0. && p->justify == RIGHT) ? 1:0) -
-            ((p->flags & PF_SPACE) ? 1:0) - p->precision - 6;
+#else
+            ((d > 0. && (p->flags & PF_PLUS)) ? 1:0) -
+#endif
+            (p->precision != 0 || (p->flags & PF_ALTFORM)) -
+            ((p->flags & PF_SPACE) ? 1:0) - p->precision - 5;
 
-  PAD_RIGHT(p);
-  PUT_PLUS(d, p, 0.);
+  if (p->pad == ' ')
+    {
+      PAD_RIGHT(p);
+      PUT_PLUS(d, p, 0.);
+    }
+  else
+    {
+      if (*tmp == '-')
+       PUT_CHAR(*tmp++, p);
+      PUT_PLUS(d, p, 0.);
+      PAD_RIGHT(p);
+    }
   PUT_SPACE(d, p, 0.);
 
   while (*tmp)
@@ -1009,7 +1129,7 @@ exponent(p, d)
     PUT_CHAR('E', p);
 
   /* the sign of the exp */
-  if (j > 0)
+  if (j >= 0)
     PUT_CHAR('+', p);
   else
     {
@@ -1029,6 +1149,7 @@ exponent(p, d)
        PUT_CHAR(*tmp, p);
        tmp++;
      }
+
    PAD_LEFT(p);
 }
 #endif
@@ -1079,7 +1200,7 @@ groupnum (s)
          else if (*g == CHAR_MAX)
            {
              do
-               *--re = *--se;
+               *--re = *--se;
              while (se > s);
              break;
            }
@@ -1149,6 +1270,7 @@ vsnprintf_internal(data, string, length, format, args)
   wint_t wc;
 #endif
   const char *convstart;
+  int negprec;
 
   /* Sanity check, the string length must be >= 0.  C99 actually says that
      LENGTH can be zero here, in the case of snprintf/vsnprintf (it's never
@@ -1164,6 +1286,7 @@ vsnprintf_internal(data, string, length, format, args)
   decpoint = thoussep = 0;
   grouping = 0;
 
+  negprec = 0;
   for (; c = *(data->pf); data->pf++)
     {
       if (c != '%')
@@ -1209,10 +1332,6 @@ vsnprintf_internal(data, string, length, format, args)
              case '#':
                data->flags |= PF_ALTFORM;
                continue;
-             case '0':
-               data->flags |= PF_ZEROPAD;
-               data->pad = '0';
-               continue;
              case '*':
                if (data->flags & PF_DOT)
                  data->flags |= PF_STAR_P;
@@ -1220,21 +1339,41 @@ vsnprintf_internal(data, string, length, format, args)
                  data->flags |= PF_STAR_W;
                continue;
              case '-':
-               data->flags |= PF_LADJUST;
-               data->justify = LEFT;
+               if ((data->flags & PF_DOT) == 0)
+                 {
+                   data->flags |= PF_LADJUST;
+                   data->justify = LEFT;
+                 }
+               else
+                 negprec = 1;
                continue;
              case ' ':
                if ((data->flags & PF_PLUS) == 0)
                  data->flags |= PF_SPACE;
                continue;
              case '+':
-               data->flags |= PF_PLUS;
-               data->justify = RIGHT;
+               if ((data->flags & PF_DOT) == 0)
+                 {
+                   data->flags |= PF_PLUS;
+                   if ((data->flags & PF_LADJUST) == 0)
+                     data->justify = RIGHT;
+                 }
                continue;
              case '\'':
                data->flags |= PF_THOUSANDS;
                continue;
 
+             case '0':
+               /* If we're not specifying precision (in which case we've seen
+                  a `.') and we're not performing left-adjustment (in which
+                  case the `0' is ignored), a `0' is taken as the zero-padding
+                  flag. */
+               if ((data->flags & (PF_DOT|PF_LADJUST)) == 0)
+                 {
+                   data->flags |= PF_ZEROPAD;
+                   data->pad = '0';
+                   continue;
+                 }
              case '1': case '2': case '3':
              case '4': case '5': case '6':
              case '7': case '8': case '9':
@@ -1249,7 +1388,7 @@ vsnprintf_internal(data, string, length, format, args)
                if (n < 0)
                  n = 0;
                if (data->flags & PF_DOT)
-                 data->precision = n;
+                 data->precision = negprec ? NOT_FOUND : n;
                else
                  data->width = n;
                continue;
@@ -1301,7 +1440,7 @@ conv_break:
                STAR_ARGS(data);
                DEF_PREC(data);
                d = GETDOUBLE(data);
-               i = log_10(d);
+               i = (d != 0.) ? log_10(d) : -1;
                /*
                 * for '%g|%G' ANSI: use f if exponent
                 * is in the range or [-4,p] exclusively
@@ -1316,8 +1455,9 @@ conv_break:
                else
                  {
                    /* reduce precision by 1 because of leading digit before
-                      decimal point in e format. */
-                   data->precision--;
+                      decimal point in e format, unless specified as 0. */
+                   if (data->precision > 0)
+                     data->precision--;
                    exponent(data, d);
                  }
                state = 0;
@@ -1506,11 +1646,21 @@ ldfallback (data, fs, fe, ld)
   char fmtbuf[FALLBACK_FMTSIZE], *obuf;
   int fl;
 
-  obuf = (char *)xmalloc(LFALLBACK_BASE + (data->precision < 6 ? 6 : data->precision) + 2);
+  fl = LFALLBACK_BASE + (data->precision < 6 ? 6 : data->precision) + 2;
+  obuf = (char *)xmalloc (fl);
   fl = fe - fs + 1;
   strncpy (fmtbuf, fs, fl);
   fmtbuf[fl] = '\0';
-  sprintf (obuf, fmtbuf, ld);
+
+  if ((data->flags & PF_STAR_W) && (data->flags & PF_STAR_P))
+    sprintf (obuf, fmtbuf, data->width, data->precision, ld);
+  else if (data->flags & PF_STAR_W)
+    sprintf (obuf, fmtbuf, data->width, ld);
+  else if (data->flags & PF_STAR_P)
+    sprintf (obuf, fmtbuf, data->precision, ld);
+  else
+    sprintf (obuf, fmtbuf, ld);
+
   for (x = obuf; *x; x++)
     PUT_CHAR (*x, data);    
   xfree (obuf);
@@ -1532,13 +1682,22 @@ dfallback (data, fs, fe, d)
   fl = fe - fs + 1;
   strncpy (fmtbuf, fs, fl);
   fmtbuf[fl] = '\0';
-  sprintf (obuf, fmtbuf, d);
+
+  if ((data->flags & PF_STAR_W) && (data->flags & PF_STAR_P))
+    sprintf (obuf, fmtbuf, data->width, data->precision, d);
+  else if (data->flags & PF_STAR_W)
+    sprintf (obuf, fmtbuf, data->width, d);
+  else if (data->flags & PF_STAR_P)
+    sprintf (obuf, fmtbuf, data->precision, d);
+  else
+    sprintf (obuf, fmtbuf, d);
+
   for (x = obuf; *x; x++)
     PUT_CHAR (*x, data);    
 }
 #endif /* FLOATING_POINT */
 
-#ifndef HAVE_SNPRINTF
+#if !HAVE_SNPRINTF
 
 int
 #if defined (__STDC__)
@@ -1588,7 +1747,7 @@ snprintf(string, length, format, va_alist)
 
 #endif /* HAVE_SNPRINTF */
 
-#ifndef HAVE_ASPRINTF
+#if !HAVE_ASPRINTF
 
 int
 #if defined (__STDC__)
@@ -1633,9 +1792,9 @@ asprintf(stringp, format, va_alist)
   return rval;
 }
 
-#endif
+#endif /* !HAVE_ASPRINTF */
 
-#endif
+#endif /* !HAVE_SNPRINTF || !HAVE_ASPRINTF */
 
 #ifdef DRIVER