home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / LIBSRC.ZOO / libsrc / stdio / vfprintf.c < prev    next >
C/C++ Source or Header  |  1992-01-25  |  23KB  |  987 lines

  1. /*-
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Chris Torek.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #if defined(LIBC_SCCS) && !defined(lint)
  38. static char sccsid[] = "@(#)vfprintf.c    5.47 (Berkeley) 3/22/91";
  39. #endif /* LIBC_SCCS and not lint */
  40.  
  41. /*
  42.  * Actual printf innards.
  43.  *
  44.  * This code is large and complicated...
  45.  */
  46.  
  47. #include <sys/types.h>
  48. #include <math.h>
  49. #include <stdio.h>
  50. #include <string.h>
  51. #if __STDC__
  52. #include <stdarg.h>
  53. #else
  54. #include <varargs.h>
  55. #endif
  56. #include "local.h"
  57. #include "fvwrite.h"
  58.  
  59. /*
  60.  * Define FLOATING_POINT to get floating point.
  61.  * Define CSH to get a csh-specific version (grr).
  62.  */
  63. #ifndef CSH
  64. #define    FLOATING_POINT
  65. #endif
  66.  
  67. /* end of configuration stuff */
  68.  
  69.  
  70. #ifdef CSH
  71. /*
  72.  * C shell hacks.  Ick, gag.
  73.  */
  74. #undef BUFSIZ
  75. #include "sh.h"
  76.  
  77. #if __STDC__
  78. int
  79. printf(const char *fmt, ...) {
  80.     FILE f;
  81.     va_list ap;
  82.     int ret;
  83.  
  84.     va_start(ap, fmt);
  85.     f._flags = __SWR;
  86.     f._write = NULL;
  87.     ret = vfprintf(&f, fmt, ap);
  88.     va_end(ap);
  89.     return ret;
  90. }
  91. #else
  92. int
  93. printf(fmt, args)
  94.     char *fmt;
  95. {
  96.     FILE f;
  97.  
  98.     f._flags = __SWR;
  99.     f._write = NULL;
  100.     return (vfprintf(&f, fmt, &args));
  101. }
  102. #endif
  103.  
  104. int
  105. __sprint(fp, uio)
  106.     FILE *fp;
  107.     register struct __suio *uio;
  108. {
  109.     register char *p;
  110.     register int n, ch, iovcnt;
  111.     register struct __siov *iov;
  112.  
  113.     /* must allow sprintf to work, might as well allow others too */
  114.     if (fp->_write || fp->_flags & __SSTR) {
  115.         if (uio->uio_resid == 0) {
  116.             uio->uio_iovcnt = 0;
  117.             return (0);
  118.         }
  119.         n = __sfvwrite(fp, uio);
  120.         uio->uio_resid = 0;
  121.         uio->uio_iovcnt = 0;
  122.         return (n);
  123.     }
  124.     iov = uio->uio_iov;
  125.     for (iovcnt = uio->uio_iovcnt; --iovcnt >= 0; iov++) {
  126.         for (p = iov->iov_base, n = iov->iov_len; --n >= 0;) {
  127. #ifdef CSHPUTCHAR
  128.             ch = *p++;
  129.             CSHPUTCHAR;    /* this horrid macro uses `ch' */
  130. #else
  131. #undef putchar
  132.             putchar(*p++);
  133. #endif
  134.         }
  135.     }
  136.     uio->uio_resid = 0;
  137.     uio->uio_iovcnt = 0;
  138.     return (0);
  139. }
  140.  
  141. #else /* CSH */
  142.  
  143. /*
  144.  * Flush out all the vectors defined by the given uio,
  145.  * then reset it so that it can be reused.
  146.  */
  147. static int
  148. __sprint(fp, uio)
  149.     FILE *fp;
  150.     register struct __suio *uio;
  151. {
  152.     register int err;
  153.  
  154.     if (uio->uio_resid == 0) {
  155.         uio->uio_iovcnt = 0;
  156.         return (0);
  157.     }
  158.     err = __sfvwrite(fp, uio);
  159.     uio->uio_resid = 0;
  160.     uio->uio_iovcnt = 0;
  161.     return (err);
  162. }
  163.  
  164. /*
  165.  * Helper function for `fprintf to unbuffered unix file': creates a
  166.  * temporary buffer.  We only work on write-only files; this avoids
  167.  * worries about ungetc buffers and so forth.
  168.  */
  169. static int
  170. __sbprintf(fp, fmt, ap)
  171.     register FILE *fp;
  172.     const char *fmt;
  173.     va_list ap;
  174. {
  175.     int ret;
  176.     FILE fake;
  177.     unsigned char buf[BUFSIZ];
  178.  
  179.     /* copy the important variables */
  180.     fake._flags = fp->_flags & ~__SNBF;
  181.     fake._file = fp->_file;
  182.     fake._cookie = fp->_cookie;
  183.     fake._write = fp->_write;
  184.  
  185.     /* set up the buffer */
  186.     fake._bf._base = fake._p = buf;
  187.     fake._bf._size = fake._w = sizeof(buf);
  188.     fake._lbfsize = 0;    /* not actually used, but Just In Case */
  189.  
  190.     /* do the work, then copy any error status */
  191.     ret = vfprintf(&fake, fmt, ap);
  192.     if (ret >= 0 && fflush(&fake))
  193.         ret = EOF;
  194.     if (fake._flags & __SERR)
  195.         fp->_flags |= __SERR;
  196.     return (ret);
  197. }
  198.  
  199. #endif /* CSH */
  200.  
  201.  
  202. #ifdef FLOATING_POINT
  203. #include "floatio.h"
  204.  
  205. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  206. #define    DEFPREC        6
  207.  
  208. static int cvt();
  209.  
  210. #else /* no FLOATING_POINT */
  211.  
  212. #define    BUF        40
  213.  
  214. #endif /* FLOATING_POINT */
  215.  
  216.  
  217. /*
  218.  * Macros for converting digits to letters and vice versa
  219.  */
  220. #define    to_digit(c)    ((c) - '0')
  221. #define is_digit(c)    ((unsigned)to_digit(c) <= 9)
  222. #define    to_char(n)    ((n) + '0')
  223.  
  224. /*
  225.  * Flags used during conversion.
  226.  */
  227. #define    LONGINT        0x01        /* long integer */
  228. #define    LONGDBL        0x02        /* long double; unimplemented */
  229. #define    SHORTINT    0x04        /* short integer */
  230. #define    ALT        0x08        /* alternate form */
  231. #define    LADJUST        0x10        /* left adjustment */
  232. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  233. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  234.  
  235. int
  236. vfprintf(fp, fmt0, ap)
  237.     FILE *fp;
  238.     const char *fmt0;
  239. #if tahoe
  240.  register /* technically illegal, since we do not know what type va_list is */
  241. #endif
  242.     va_list ap;
  243. {
  244.     register char *fmt;    /* format string */
  245.     register int ch;    /* character from fmt */
  246.     register int n;        /* handy integer (short term usage) */
  247.     register char *cp;    /* handy char pointer (short term usage) */
  248.     register struct __siov *iovp;/* for PRINT macro */
  249.     register int flags;    /* flags as above */
  250.     int ret;        /* return value accumulator */
  251.     int width;        /* width from format (%8d), or 0 */
  252.     int prec;        /* precision from format (%.3d), or -1 */
  253.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  254. #ifdef FLOATING_POINT
  255.     char softsign;        /* temporary negative sign for floats */
  256.     double _double;        /* double precision arguments %[eEfgG] */
  257.     int fpprec;        /* `extra' floating precision in [eEfgG] */
  258. #endif
  259.     u_long _ulong;        /* integer arguments %[diouxX] */
  260.     enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
  261.     int dprec;        /* a copy of prec if [diouxX], 0 otherwise */
  262.     int fieldsz;        /* field size expanded by sign, etc */
  263.     int realsz;        /* field size expanded by dprec */
  264.     int size;        /* size of converted field or string */
  265.     char *xdigs;        /* digits for [xX] conversion */
  266. #define NIOV 8
  267.     struct __suio uio;    /* output information: summary */
  268.     struct __siov iov[NIOV];/* ... and individual io vectors */
  269.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  270.     char ox[2];        /* space for 0x hex-prefix */
  271.  
  272.     /*
  273.      * Choose PADSIZE to trade efficiency vs size.  If larger
  274.      * printf fields occur frequently, increase PADSIZE (and make
  275.      * the initialisers below longer).
  276.      */
  277. #define    PADSIZE    16        /* pad chunk size */
  278.     static char blanks[PADSIZE] =
  279.      {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
  280.     static char zeroes[PADSIZE] =
  281.      {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
  282.  
  283.     /*
  284.      * BEWARE, these `goto error' on error, and PAD uses `n'.
  285.      */
  286. #define    PRINT(ptr, len) { \
  287.     iovp->iov_base = (ptr); \
  288.     iovp->iov_len = (len); \
  289.     uio.uio_resid += (len); \
  290.     iovp++; \
  291.     if (++uio.uio_iovcnt >= NIOV) { \
  292.         if (__sprint(fp, &uio)) \
  293.             goto error; \
  294.         iovp = iov; \
  295.     } \
  296. }
  297. #define    PAD(howmany, with) { \
  298.     if ((n = (howmany)) > 0) { \
  299.         while (n > PADSIZE) { \
  300.             PRINT(with, PADSIZE); \
  301.             n -= PADSIZE; \
  302.         } \
  303.         PRINT(with, n); \
  304.     } \
  305. }
  306. #define    FLUSH() { \
  307.     if (uio.uio_resid && __sprint(fp, &uio)) \
  308.         goto error; \
  309.     uio.uio_iovcnt = 0; \
  310.     iovp = iov; \
  311. }
  312.  
  313.     /*
  314.      * To extend shorts properly, we need both signed and unsigned
  315.      * argument extraction methods.
  316.      */
  317. #define    SARG() \
  318.     (flags&LONGINT ? va_arg(ap, long) : \
  319.         flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
  320.         (long)va_arg(ap, int))
  321. #define    UARG() \
  322.     (flags&LONGINT ? va_arg(ap, u_long) : \
  323.         flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
  324.         (u_long)va_arg(ap, u_int))
  325.  
  326. #ifndef CSH
  327.     /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
  328.     if (cantwrite(fp))
  329.         return (EOF);
  330.  
  331.     /* optimise fprintf(stderr) (and other unbuffered Unix files) */
  332.     if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
  333.         fp->_file >= 0)
  334.         return (__sbprintf(fp, fmt0, ap));
  335. #endif /* CSH */
  336.  
  337.     fmt = (char *)fmt0;
  338.     uio.uio_iov = iovp = iov;
  339.     uio.uio_resid = 0;
  340.     uio.uio_iovcnt = 0;
  341.     ret = 0;
  342.  
  343.     /*
  344.      * Scan the format for conversions (`%' character).
  345.      */
  346.     for (;;) {
  347.         for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
  348.             /* void */;
  349.         if ((n = fmt - cp) != 0) {
  350.             PRINT(cp, n);
  351.             ret += n;
  352.         }
  353.         if (ch == '\0')
  354.             goto done;
  355.         fmt++;        /* skip over '%' */
  356.  
  357.         flags = 0;
  358.         dprec = 0;
  359. #ifdef FLOATING_POINT
  360.         fpprec = 0;
  361. #endif
  362.         width = 0;
  363.         prec = -1;
  364.         sign = '\0';
  365.  
  366. rflag:        ch = *fmt++;
  367. reswitch:    switch (ch) {
  368.         case ' ':
  369.             /*
  370.              * ``If the space and + flags both appear, the space
  371.              * flag will be ignored.''
  372.              *    -- ANSI X3J11
  373.              */
  374.             if (!sign)
  375.                 sign = ' ';
  376.             goto rflag;
  377.         case '#':
  378.             flags |= ALT;
  379.             goto rflag;
  380.         case '*':
  381.             /*
  382.              * ``A negative field width argument is taken as a
  383.              * - flag followed by a positive field width.''
  384.              *    -- ANSI X3J11
  385.              * They don't exclude field widths read from args.
  386.              */
  387.             if ((width = va_arg(ap, int)) >= 0)
  388.                 goto rflag;
  389.             width = -width;
  390.             /* FALLTHROUGH */
  391.         case '-':
  392.             flags |= LADJUST;
  393.             goto rflag;
  394.         case '+':
  395.             sign = '+';
  396.             goto rflag;
  397.         case '.':
  398.             if ((ch = *fmt++) == '*') {
  399.                 n = va_arg(ap, int);
  400.                 prec = n < 0 ? -1 : n;
  401.                 goto rflag;
  402.             }
  403.             n = 0;
  404.             while (is_digit(ch)) {
  405.                 n = 10 * n + to_digit(ch);
  406.                 ch = *fmt++;
  407.             }
  408.             prec = n < 0 ? -1 : n;
  409.             goto reswitch;
  410.         case '0':
  411.             /*
  412.              * ``Note that 0 is taken as a flag, not as the
  413.              * beginning of a field width.''
  414.              *    -- ANSI X3J11
  415.              */
  416.             flags |= ZEROPAD;
  417.             goto rflag;
  418.         case '1': case '2': case '3': case '4':
  419.         case '5': case '6': case '7': case '8': case '9':
  420.             n = 0;
  421.             do {
  422.                 n = 10 * n + to_digit(ch);
  423.                 ch = *fmt++;
  424.             } while (is_digit(ch));
  425.             width = n;
  426.             goto reswitch;
  427. #ifdef FLOATING_POINT
  428.         case 'L':
  429.             flags |= LONGDBL;
  430.             goto rflag;
  431. #endif
  432.         case 'h':
  433.             flags |= SHORTINT;
  434.             goto rflag;
  435.         case 'l':
  436.             flags |= LONGINT;
  437.             goto rflag;
  438.         case 'c':
  439.             *(cp = buf) = va_arg(ap, int);
  440.             size = 1;
  441.             sign = '\0';
  442.             break;
  443.         case 'D':
  444.             flags |= LONGINT;
  445.             /*FALLTHROUGH*/
  446.         case 'd':
  447.         case 'i':
  448.             _ulong = SARG();
  449.             if ((long)_ulong < 0) {
  450.                 _ulong = -_ulong;
  451.                 sign = '-';
  452.             }
  453.             base = DEC;
  454.             goto number;
  455. #ifdef FLOATING_POINT
  456.         case 'e':
  457.         case 'E':
  458.         case 'f':
  459.         case 'g':
  460.         case 'G':
  461.             _double = va_arg(ap, double);
  462.             /* do this before tricky precision changes */
  463.             if (isinf(_double)) {
  464.                 if (_double < 0)
  465.                     sign = '-';
  466.                 cp = "Inf";
  467.                 size = 3;
  468.                 break;
  469.             }
  470.             if (isnan(_double)) {
  471.                 cp = "NaN";
  472.                 size = 3;
  473.                 break;
  474.             }
  475.             /*
  476.              * don't do unrealistic precision; just pad it with
  477.              * zeroes later, so buffer size stays rational.
  478.              */
  479.             if (prec > MAXFRACT) {
  480.                 if (ch != 'g' && ch != 'G' || (flags&ALT))
  481.                     fpprec = prec - MAXFRACT;
  482.                 prec = MAXFRACT;
  483.             } else if (prec == -1)
  484.                 prec = DEFPREC;
  485.             /*
  486.              * cvt may have to round up before the "start" of
  487.              * its buffer, i.e. ``intf("%.2f", (double)9.999);'';
  488.              * if the first character is still NUL, it did.
  489.              * softsign avoids negative 0 if _double < 0 but
  490.              * no significant digits will be shown.
  491.              */
  492.             cp = buf;
  493.             *cp = '\0';
  494.             size = cvt(_double, prec, flags, &softsign, ch,
  495.                 cp, buf + sizeof(buf));
  496.             if (softsign)
  497.                 sign = '-';
  498.             if (*cp == '\0')
  499.                 cp++;
  500.             break;
  501. #endif /* FLOATING_POINT */
  502.         case 'n':
  503.             if (flags & LONGINT)
  504.                 *va_arg(ap, long *) = ret;
  505.             else if (flags & SHORTINT)
  506.                 *va_arg(ap, short *) = ret;
  507.             else
  508.                 *va_arg(ap, int *) = ret;
  509.             continue;    /* no output */
  510.         case 'O':
  511.             flags |= LONGINT;
  512.             /*FALLTHROUGH*/
  513.         case 'o':
  514.             _ulong = UARG();
  515.             base = OCT;
  516.             goto nosign;
  517.         case 'p':
  518.             /*
  519.              * ``The argument shall be a pointer to void.  The
  520.              * value of the pointer is converted to a sequence
  521.              * of printable characters, in an implementation-
  522.              * defined manner.''
  523.              *    -- ANSI X3J11
  524.              */
  525.             /* NOSTRICT */
  526.             _ulong = (u_long)va_arg(ap, void *);
  527.             base = HEX;
  528.             xdigs = "0123456789abcdef";
  529.             flags |= HEXPREFIX;
  530.             ch = 'x';
  531.             goto nosign;
  532.         case 's':
  533.             if ((cp = va_arg(ap, char *)) == NULL)
  534.                 cp = "(null)";
  535.             if (prec >= 0) {
  536.                 /*
  537.                  * can't use strlen; can only look for the
  538.                  * NUL in the first `prec' characters, and
  539.                  * strlen() will go further.
  540.                  */
  541.                 char *p = memchr(cp, 0, prec);
  542.  
  543.                 if (p != NULL) {
  544.                     size = p - cp;
  545.                     if (size > prec)
  546.                         size = prec;
  547.                 } else
  548.                     size = prec;
  549.             } else
  550.                 size = strlen(cp);
  551.             sign = '\0';
  552.             break;
  553.         case 'U':
  554.             flags |= LONGINT;
  555.             /*FALLTHROUGH*/
  556.         case 'u':
  557.             _ulong = UARG();
  558.             base = DEC;
  559.             goto nosign;
  560.         case 'X':
  561.             xdigs = "0123456789ABCDEF";
  562.             goto hex;
  563.         case 'x':
  564.             xdigs = "0123456789abcdef";
  565. hex:            _ulong = UARG();
  566.             base = HEX;
  567.             /* leading 0x/X only if non-zero */
  568.             if (flags & ALT && _ulong != 0)
  569.                 flags |= HEXPREFIX;
  570.  
  571.             /* unsigned conversions */
  572. nosign:            sign = '\0';
  573.             /*
  574.              * ``... diouXx conversions ... if a precision is
  575.              * specified, the 0 flag will be ignored.''
  576.              *    -- ANSI X3J11
  577.              */
  578. number:            if ((dprec = prec) >= 0)
  579.                 flags &= ~ZEROPAD;
  580.  
  581.             /*
  582.              * ``The result of converting a zero value with an
  583.              * explicit precision of zero is no characters.''
  584.              *    -- ANSI X3J11
  585.              */
  586.             cp = buf + BUF;
  587.             if (_ulong != 0 || prec != 0) {
  588.                 /*
  589.                  * unsigned mod is hard, and unsigned mod
  590.                  * by a constant is easier than that by
  591.                  * a variable; hence this switch.
  592.                  */
  593.                 switch (base) {
  594.                 case OCT:
  595.                     do {
  596.                         *--cp = to_char(_ulong & 7);
  597.                         _ulong >>= 3;
  598.                     } while (_ulong);
  599.                     /* handle octal leading 0 */
  600.                     if (flags & ALT && *cp != '0')
  601.                         *--cp = '0';
  602.                     break;
  603.  
  604.                 case DEC:
  605.                     /* many numbers are 1 digit */
  606.                     while (_ulong >= 10) {
  607.                         *--cp = to_char(_ulong % 10);
  608.                         _ulong /= 10;
  609.                     }
  610.                     *--cp = to_char(_ulong);
  611.                     break;
  612.  
  613.                 case HEX:
  614.                     do {
  615.                         *--cp = xdigs[_ulong & 15];
  616.                         _ulong >>= 4;
  617.                     } while (_ulong);
  618.                     break;
  619.  
  620.                 default:
  621.                     cp = "bug in vfprintf: bad base";
  622.                     size = strlen(cp);
  623.                     goto skipsize;
  624.                 }
  625.             }
  626.             size = buf + BUF - cp;
  627.         skipsize:
  628.             break;
  629.         default:    /* "%?" prints ?, unless ? is NUL */
  630.             if (ch == '\0')
  631.                 goto done;
  632.             /* pretend it was %c with argument ch */
  633.             cp = buf;
  634.             *cp = ch;
  635.             size = 1;
  636.             sign = '\0';
  637.             break;
  638.         }
  639.  
  640.         /*
  641.          * All reasonable formats wind up here.  At this point,
  642.          * `cp' points to a string which (if not flags&LADJUST)
  643.          * should be padded out to `width' places.  If
  644.          * flags&ZEROPAD, it should first be prefixed by any
  645.          * sign or other prefix; otherwise, it should be blank
  646.          * padded before the prefix is emitted.  After any
  647.          * left-hand padding and prefixing, emit zeroes
  648.          * required by a decimal [diouxX] precision, then print
  649.          * the string proper, then emit zeroes required by any
  650.          * leftover floating precision; finally, if LADJUST,
  651.          * pad with blanks.
  652.          */
  653.  
  654.         /*
  655.          * compute actual size, so we know how much to pad.
  656.          * fieldsz excludes decimal prec; realsz includes it
  657.          */
  658. #ifdef FLOATING_POINT
  659.         fieldsz = size + fpprec;
  660. #else
  661.         fieldsz = size;
  662. #endif
  663.         if (sign)
  664.             fieldsz++;
  665.         else if (flags & HEXPREFIX)
  666.             fieldsz += 2;
  667.         realsz = dprec > fieldsz ? dprec : fieldsz;
  668.  
  669.         /* right-adjusting blank padding */
  670.         if ((flags & (LADJUST|ZEROPAD)) == 0)
  671.             PAD(width - realsz, blanks);
  672.  
  673.         /* prefix */
  674.         if (sign) {
  675.             PRINT(&sign, 1);
  676.         } else if (flags & HEXPREFIX) {
  677.             ox[0] = '0';
  678.             ox[1] = ch;
  679.             PRINT(ox, 2);
  680.         }
  681.  
  682.         /* right-adjusting zero padding */
  683.         if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  684.             PAD(width - realsz, zeroes);
  685.  
  686.         /* leading zeroes from decimal precision */
  687.         PAD(dprec - fieldsz, zeroes);
  688.  
  689.         /* the string or number proper */
  690.         PRINT(cp, size);
  691.  
  692. #ifdef FLOATING_POINT
  693.         /* trailing f.p. zeroes */
  694.         PAD(fpprec, zeroes);
  695. #endif
  696.  
  697.         /* left-adjusting padding (always blank) */
  698.         if (flags & LADJUST)
  699.             PAD(width - realsz, blanks);
  700.  
  701.         /* finally, adjust ret */
  702.         ret += width > realsz ? width : realsz;
  703.  
  704.         FLUSH();    /* copy out the I/O vectors */
  705.     }
  706. done:
  707.     FLUSH();
  708. error:
  709.     return (__sferror(fp) ? EOF : ret);
  710.     /* NOTREACHED */
  711. }
  712.  
  713. #ifdef FLOATING_POINT
  714. #include <math.h>
  715.  
  716. static char *exponent();
  717. static char *round();
  718.  
  719. static int
  720. cvt(number, prec, flags, signp, fmtch, startp, endp)
  721.     double number;
  722.     register int prec;
  723.     int flags;
  724.     char *signp;
  725.     int fmtch;
  726.     char *startp, *endp;
  727. {
  728.     register char *p, *t;
  729.     register double fract;
  730.     int dotrim, expcnt, gformat;
  731.     double integer, tmp;
  732.  
  733.     dotrim = expcnt = gformat = 0;
  734.     if (number < 0) {
  735.         number = -number;
  736.         *signp = '-';
  737.     } else
  738.         *signp = 0;
  739.  
  740.     fract = modf(number, &integer);
  741.  
  742.     /* get an extra slot for rounding. */
  743.     t = ++startp;
  744.  
  745.     /*
  746.      * get integer portion of number; put into the end of the buffer; the
  747.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  748.      */
  749.     for (p = endp - 1; integer; ++expcnt) {
  750.         tmp = modf(integer / 10, &integer);
  751.         *p-- = to_char((int)((tmp + .01) * 10));
  752.     }
  753.     switch (fmtch) {
  754.     case 'f':
  755.         /* reverse integer into beginning of buffer */
  756.         if (expcnt)
  757.             for (; ++p < endp; *t++ = *p);
  758.         else
  759.             *t++ = '0';
  760.         /*
  761.          * if precision required or alternate flag set, add in a
  762.          * decimal point.
  763.          */
  764.         if (prec || flags&ALT)
  765.             *t++ = '.';
  766.         /* if requires more precision and some fraction left */
  767.         if (fract) {
  768.             if (prec)
  769.                 do {
  770.                     fract = modf(fract * 10, &tmp);
  771.                     *t++ = to_char((int)tmp);
  772.                 } while (--prec && fract);
  773.             if (fract)
  774.                 startp = round(fract, (int *)NULL, startp,
  775.                     t - 1, (char)0, signp);
  776.         }
  777.         for (; prec--; *t++ = '0');
  778.         break;
  779.     case 'e':
  780.     case 'E':
  781. eformat:    if (expcnt) {
  782.             *t++ = *++p;
  783.             if (prec || flags&ALT)
  784.                 *t++ = '.';
  785.             /* if requires more precision and some integer left */
  786.             for (; prec && ++p < endp; --prec)
  787.                 *t++ = *p;
  788.             /*
  789.              * if done precision and more of the integer component,
  790.              * round using it; adjust fract so we don't re-round
  791.              * later.
  792.              */
  793.             if (!prec && ++p < endp) {
  794.                 fract = 0;
  795.                 startp = round((double)0, &expcnt, startp,
  796.                     t - 1, *p, signp);
  797.             }
  798.             /* adjust expcnt for digit in front of decimal */
  799.             --expcnt;
  800.         }
  801.         /* until first fractional digit, decrement exponent */
  802.         else if (fract) {
  803.             /* adjust expcnt for digit in front of decimal */
  804.             for (expcnt = -1;; --expcnt) {
  805.                 fract = modf(fract * 10, &tmp);
  806.                 if (tmp)
  807.                     break;
  808.             }
  809.             *t++ = to_char((int)tmp);
  810.             if (prec || flags&ALT)
  811.                 *t++ = '.';
  812.         }
  813.         else {
  814.             *t++ = '0';
  815.             if (prec || flags&ALT)
  816.                 *t++ = '.';
  817.         }
  818.         /* if requires more precision and some fraction left */
  819.         if (fract) {
  820.             if (prec)
  821.                 do {
  822.                     fract = modf(fract * 10, &tmp);
  823.                     *t++ = to_char((int)tmp);
  824.                 } while (--prec && fract);
  825.             if (fract)
  826.                 startp = round(fract, &expcnt, startp,
  827.                     t - 1, (char)0, signp);
  828.         }
  829.         /* if requires more precision */
  830.         for (; prec--; *t++ = '0');
  831.  
  832.         /* unless alternate flag, trim any g/G format trailing 0's */
  833.         if (gformat && !(flags&ALT)) {
  834.             while (t > startp && *--t == '0');
  835.             if (*t == '.')
  836.                 --t;
  837.             ++t;
  838.         }
  839.         t = exponent(t, expcnt, fmtch);
  840.         break;
  841.     case 'g':
  842.     case 'G':
  843.         /* a precision of 0 is treated as a precision of 1. */
  844.         if (!prec)
  845.             ++prec;
  846.         /*
  847.          * ``The style used depends on the value converted; style e
  848.          * will be used only if the exponent resulting from the
  849.          * conversion is less than -4 or greater than the precision.''
  850.          *    -- ANSI X3J11
  851.          */
  852.         if (expcnt > prec || !expcnt && fract && fract < .0001) {
  853.             /*
  854.              * g/G format counts "significant digits, not digits of
  855.              * precision; for the e/E format, this just causes an
  856.              * off-by-one problem, i.e. g/G considers the digit
  857.              * before the decimal point significant and e/E doesn't
  858.              * count it as precision.
  859.              */
  860.             --prec;
  861.             fmtch -= 2;        /* G->E, g->e */
  862.             gformat = 1;
  863.             goto eformat;
  864.         }
  865.         /*
  866.          * reverse integer into beginning of buffer,
  867.          * note, decrement precision
  868.          */
  869.         if (expcnt)
  870.             for (; ++p < endp; *t++ = *p, --prec);
  871.         else
  872.             *t++ = '0';
  873.         /*
  874.          * if precision required or alternate flag set, add in a
  875.          * decimal point.  If no digits yet, add in leading 0.
  876.          */
  877.         if (prec || flags&ALT) {
  878.             dotrim = 1;
  879.             *t++ = '.';
  880.         }
  881.         else
  882.             dotrim = 0;
  883.         /* if requires more precision and some fraction left */
  884.         if (fract) {
  885.             if (prec) {
  886.                 do {
  887.                     fract = modf(fract * 10, &tmp);
  888.                     *t++ = to_char((int)tmp);
  889.                 } while(!tmp);
  890.                 while (--prec && fract) {
  891.                     fract = modf(fract * 10, &tmp);
  892.                     *t++ = to_char((int)tmp);
  893.                 }
  894.             }
  895.             if (fract)
  896.                 startp = round(fract, (int *)NULL, startp,
  897.                     t - 1, (char)0, signp);
  898.         }
  899.         /* alternate format, adds 0's for precision, else trim 0's */
  900.         if (flags&ALT)
  901.             for (; prec--; *t++ = '0');
  902.         else if (dotrim) {
  903.             while (t > startp && *--t == '0');
  904.             if (*t != '.')
  905.                 ++t;
  906.         }
  907.     }
  908.     return (t - startp);
  909. }
  910.  
  911. static char *
  912. round(fract, exp, start, end, ch, signp)
  913.     double fract;
  914.     int *exp;
  915.     register char *start, *end;
  916.     char ch, *signp;
  917. {
  918.     double tmp;
  919.  
  920.     if (fract)
  921.         (void)modf(fract * 10, &tmp);
  922.     else
  923.         tmp = to_digit(ch);
  924.     if (tmp > 4)
  925.         for (;; --end) {
  926.             if (*end == '.')
  927.                 --end;
  928.             if (++*end <= '9')
  929.                 break;
  930.             *end = '0';
  931.             if (end == start) {
  932.                 if (exp) {    /* e/E; increment exponent */
  933.                     *end = '1';
  934.                     ++*exp;
  935.                 }
  936.                 else {        /* f; add extra digit */
  937.                 *--end = '1';
  938.                 --start;
  939.                 }
  940.                 break;
  941.             }
  942.         }
  943.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  944.     else if (*signp == '-')
  945.         for (;; --end) {
  946.             if (*end == '.')
  947.                 --end;
  948.             if (*end != '0')
  949.                 break;
  950.             if (end == start)
  951.                 *signp = 0;
  952.         }
  953.     return (start);
  954. }
  955.  
  956. static char *
  957. exponent(p, exp, fmtch)
  958.     register char *p;
  959.     register int exp;
  960.     int fmtch;
  961. {
  962.     register char *t;
  963.     char expbuf[MAXEXP];
  964.  
  965.     *p++ = fmtch;
  966.     if (exp < 0) {
  967.         exp = -exp;
  968.         *p++ = '-';
  969.     }
  970.     else
  971.         *p++ = '+';
  972.     t = expbuf + MAXEXP;
  973.     if (exp > 9) {
  974.         do {
  975.             *--t = to_char(exp % 10);
  976.         } while ((exp /= 10) > 9);
  977.         *--t = to_char(exp);
  978.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  979.     }
  980.     else {
  981.         *p++ = '0';
  982.         *p++ = to_char(exp);
  983.     }
  984.     return (p);
  985. }
  986. #endif /* FLOATING_POINT */
  987.