home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / lib / libc / stdio / vfprintf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-16  |  18.0 KB  |  756 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.50 (Berkeley) 12/16/92";
  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.  
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <string.h>
  52.  
  53. #if __STDC__
  54. #include <stdarg.h>
  55. #else
  56. #include <varargs.h>
  57. #endif
  58.  
  59. #include "local.h"
  60. #include "fvwrite.h"
  61.  
  62. /* Define FLOATING_POINT to get floating point. */
  63. #define    FLOATING_POINT
  64.  
  65. /*
  66.  * Flush out all the vectors defined by the given uio,
  67.  * then reset it so that it can be reused.
  68.  */
  69. static int
  70. __sprint(fp, uio)
  71.     FILE *fp;
  72.     register struct __suio *uio;
  73. {
  74.     register int err;
  75.  
  76.     if (uio->uio_resid == 0) {
  77.         uio->uio_iovcnt = 0;
  78.         return (0);
  79.     }
  80.     err = __sfvwrite(fp, uio);
  81.     uio->uio_resid = 0;
  82.     uio->uio_iovcnt = 0;
  83.     return (err);
  84. }
  85.  
  86. /*
  87.  * Helper function for `fprintf to unbuffered unix file': creates a
  88.  * temporary buffer.  We only work on write-only files; this avoids
  89.  * worries about ungetc buffers and so forth.
  90.  */
  91. static int
  92. __sbprintf(fp, fmt, ap)
  93.     register FILE *fp;
  94.     const char *fmt;
  95.     va_list ap;
  96. {
  97.     int ret;
  98.     FILE fake;
  99.     unsigned char buf[BUFSIZ];
  100.  
  101.     /* copy the important variables */
  102.     fake._flags = fp->_flags & ~__SNBF;
  103.     fake._file = fp->_file;
  104.     fake._cookie = fp->_cookie;
  105.     fake._write = fp->_write;
  106.  
  107.     /* set up the buffer */
  108.     fake._bf._base = fake._p = buf;
  109.     fake._bf._size = fake._w = sizeof(buf);
  110.     fake._lbfsize = 0;    /* not actually used, but Just In Case */
  111.  
  112.     /* do the work, then copy any error status */
  113.     ret = vfprintf(&fake, fmt, ap);
  114.     if (ret >= 0 && fflush(&fake))
  115.         ret = EOF;
  116.     if (fake._flags & __SERR)
  117.         fp->_flags |= __SERR;
  118.     return (ret);
  119. }
  120.  
  121.  
  122. #ifdef FLOATING_POINT
  123. #include <math.h>
  124. #include "floatio.h"
  125.  
  126. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  127. #define    DEFPREC        6
  128.  
  129. static char *cvt __P((double, int, int, char *, int *, int, int *));
  130. static int exponent __P((char *, int, int));
  131.  
  132. #else /* no FLOATING_POINT */
  133.  
  134. #define    BUF        40
  135.  
  136. #endif /* FLOATING_POINT */
  137.  
  138.  
  139. /*
  140.  * Macros for converting digits to letters and vice versa
  141.  */
  142. #define    to_digit(c)    ((c) - '0')
  143. #define is_digit(c)    ((unsigned)to_digit(c) <= 9)
  144. #define    to_char(n)    ((n) + '0')
  145.  
  146. /*
  147.  * Flags used during conversion.
  148.  */
  149. #define    ALT        0x001        /* alternate form */
  150. #define    HEXPREFIX    0x002        /* add 0x or 0X prefix */
  151. #define    LADJUST        0x004        /* left adjustment */
  152. #define    LONGDBL        0x008        /* long double; unimplemented */
  153. #define    LONGINT        0x010        /* long integer */
  154. #define    QUADINT        0x020        /* quad integer */
  155. #define    SHORTINT    0x040        /* short integer */
  156. #define    ZEROPAD        0x080        /* zero (as opposed to blank) pad */
  157. #define FPT        0x100        /* Floating point number */
  158. int
  159. vfprintf(fp, fmt0, ap)
  160.     FILE *fp;
  161.     const char *fmt0;
  162.     va_list ap;
  163. {
  164.     register char *fmt;    /* format string */
  165.     register int ch;    /* character from fmt */
  166.     register int n;        /* handy integer (short term usage) */
  167.     register char *cp;    /* handy char pointer (short term usage) */
  168.     register struct __siov *iovp;/* for PRINT macro */
  169.     register int flags;    /* flags as above */
  170.     int ret;        /* return value accumulator */
  171.     int width;        /* width from format (%8d), or 0 */
  172.     int prec;        /* precision from format (%.3d), or -1 */
  173.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  174. #ifdef FLOATING_POINT
  175.     char softsign;        /* temporary negative sign for floats */
  176.     double _double;        /* double precision arguments %[eEfgG] */
  177.     int expt;        /* integer value of exponent */
  178.     int expsize;        /* character count for expstr */
  179.     int ndig;        /* actual number of digits returned by cvt */
  180.     char expstr[7];        /* buffer for exponent string */
  181. #endif
  182.     u_quad_t _uquad;    /* integer arguments %[diouxX] */
  183.     enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
  184.     int dprec;        /* a copy of prec if [diouxX], 0 otherwise */
  185.     int fieldsz;        /* field size expanded by sign, etc */
  186.     int realsz;        /* field size expanded by dprec */
  187.     int size;        /* size of converted field or string */
  188.     char *xdigs;        /* digits for [xX] conversion */
  189. #define NIOV 8
  190.     struct __suio uio;    /* output information: summary */
  191.     struct __siov iov[NIOV];/* ... and individual io vectors */
  192.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  193.     char ox[2];        /* space for 0x hex-prefix */
  194.  
  195.     /*
  196.      * Choose PADSIZE to trade efficiency vs. size.  If larger printf
  197.      * fields occur frequently, increase PADSIZE and make the initialisers
  198.      * below longer.
  199.      */
  200. #define    PADSIZE    16        /* pad chunk size */
  201.     static char blanks[PADSIZE] =
  202.      {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
  203.     static char zeroes[PADSIZE] =
  204.      {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
  205.  
  206.     /*
  207.      * BEWARE, these `goto error' on error, and PAD uses `n'.
  208.      */
  209. #define    PRINT(ptr, len) { \
  210.     iovp->iov_base = (ptr); \
  211.     iovp->iov_len = (len); \
  212.     uio.uio_resid += (len); \
  213.     iovp++; \
  214.     if (++uio.uio_iovcnt >= NIOV) { \
  215.         if (__sprint(fp, &uio)) \
  216.             goto error; \
  217.         iovp = iov; \
  218.     } \
  219. }
  220. #define    PAD(howmany, with) { \
  221.     if ((n = (howmany)) > 0) { \
  222.         while (n > PADSIZE) { \
  223.             PRINT(with, PADSIZE); \
  224.             n -= PADSIZE; \
  225.         } \
  226.         PRINT(with, n); \
  227.     } \
  228. }
  229. #define    FLUSH() { \
  230.     if (uio.uio_resid && __sprint(fp, &uio)) \
  231.         goto error; \
  232.     uio.uio_iovcnt = 0; \
  233.     iovp = iov; \
  234. }
  235.  
  236.     /*
  237.      * To extend shorts properly, we need both signed and unsigned
  238.      * argument extraction methods.
  239.      */
  240. #define    SARG() \
  241.     (flags&QUADINT ? va_arg(ap, quad_t) : \
  242.         flags&LONGINT ? va_arg(ap, long) : \
  243.         flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
  244.         (long)va_arg(ap, int))
  245. #define    UARG() \
  246.     (flags&QUADINT ? va_arg(ap, u_quad_t) : \
  247.         flags&LONGINT ? va_arg(ap, u_long) : \
  248.         flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
  249.         (u_long)va_arg(ap, u_int))
  250.  
  251.     /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
  252.     if (cantwrite(fp))
  253.         return (EOF);
  254.  
  255.     /* optimise fprintf(stderr) (and other unbuffered Unix files) */
  256.     if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
  257.         fp->_file >= 0)
  258.         return (__sbprintf(fp, fmt0, ap));
  259.  
  260.     fmt = (char *)fmt0;
  261.     uio.uio_iov = iovp = iov;
  262.     uio.uio_resid = 0;
  263.     uio.uio_iovcnt = 0;
  264.     ret = 0;
  265.  
  266.     /*
  267.      * Scan the format for conversions (`%' character).
  268.      */
  269.     for (;;) {
  270.         for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
  271.             /* void */;
  272.         if ((n = fmt - cp) != 0) {
  273.             PRINT(cp, n);
  274.             ret += n;
  275.         }
  276.         if (ch == '\0')
  277.             goto done;
  278.         fmt++;        /* skip over '%' */
  279.  
  280.         flags = 0;
  281.         dprec = 0;
  282.         width = 0;
  283.         prec = -1;
  284.         sign = '\0';
  285.  
  286. rflag:        ch = *fmt++;
  287. reswitch:    switch (ch) {
  288.         case ' ':
  289.             /*
  290.              * ``If the space and + flags both appear, the space
  291.              * flag will be ignored.''
  292.              *    -- ANSI X3J11
  293.              */
  294.             if (!sign)
  295.                 sign = ' ';
  296.             goto rflag;
  297.         case '#':
  298.             flags |= ALT;
  299.             goto rflag;
  300.         case '*':
  301.             /*
  302.              * ``A negative field width argument is taken as a
  303.              * - flag followed by a positive field width.''
  304.              *    -- ANSI X3J11
  305.              * They don't exclude field widths read from args.
  306.              */
  307.             if ((width = va_arg(ap, int)) >= 0)
  308.                 goto rflag;
  309.             width = -width;
  310.             /* FALLTHROUGH */
  311.         case '-':
  312.             flags |= LADJUST;
  313.             goto rflag;
  314.         case '+':
  315.             sign = '+';
  316.             goto rflag;
  317.         case '.':
  318.             if ((ch = *fmt++) == '*') {
  319.                 n = va_arg(ap, int);
  320.                 prec = n < 0 ? -1 : n;
  321.                 goto rflag;
  322.             }
  323.             n = 0;
  324.             while (is_digit(ch)) {
  325.                 n = 10 * n + to_digit(ch);
  326.                 ch = *fmt++;
  327.             }
  328.             prec = n < 0 ? -1 : n;
  329.             goto reswitch;
  330.         case '0':
  331.             /*
  332.              * ``Note that 0 is taken as a flag, not as the
  333.              * beginning of a field width.''
  334.              *    -- ANSI X3J11
  335.              */
  336.             flags |= ZEROPAD;
  337.             goto rflag;
  338.         case '1': case '2': case '3': case '4':
  339.         case '5': case '6': case '7': case '8': case '9':
  340.             n = 0;
  341.             do {
  342.                 n = 10 * n + to_digit(ch);
  343.                 ch = *fmt++;
  344.             } while (is_digit(ch));
  345.             width = n;
  346.             goto reswitch;
  347. #ifdef FLOATING_POINT
  348.         case 'L':
  349.             flags |= LONGDBL;
  350.             goto rflag;
  351. #endif
  352.         case 'h':
  353.             flags |= SHORTINT;
  354.             goto rflag;
  355.         case 'l':
  356.             flags |= LONGINT;
  357.             goto rflag;
  358.         case 'q':
  359.             flags |= QUADINT;
  360.             goto rflag;
  361.         case 'c':
  362.             *(cp = buf) = va_arg(ap, int);
  363.             size = 1;
  364.             sign = '\0';
  365.             break;
  366.         case 'D':
  367.             flags |= LONGINT;
  368.             /*FALLTHROUGH*/
  369.         case 'd':
  370.         case 'i':
  371.             _uquad = SARG();
  372.             if ((quad_t)_uquad < 0) {
  373.                 _uquad = -_uquad;
  374.                 sign = '-';
  375.             }
  376.             base = DEC;
  377.             goto number;
  378. #ifdef FLOATING_POINT
  379.         case 'e':        /* anomalous precision */
  380.         case 'E':
  381.             prec = (prec == -1) ?
  382.                 DEFPREC + 1 : prec + 1;
  383.             /* FALLTHROUGH */
  384.             goto fp_begin;
  385.         case 'f':        /* always print trailing zeroes */
  386.             if (prec != 0)
  387.                 flags |= ALT;
  388.         case 'g':
  389.         case 'G':
  390.             if (prec == -1)
  391.                 prec = DEFPREC;
  392. fp_begin:        _double = va_arg(ap, double);
  393.             /* do this before tricky precision changes */
  394.             if (isinf(_double)) {
  395.                 if (_double < 0)
  396.                     sign = '-';
  397.                 cp = "Inf";
  398.                 size = 3;
  399.                 break;
  400.             }
  401.             if (isnan(_double)) {
  402.                 cp = "NaN";
  403.                 size = 3;
  404.                 break;
  405.             }
  406.             flags |= FPT;
  407.             cp = cvt(_double, prec, flags, &softsign,
  408.                 &expt, ch, &ndig);
  409.             if (ch == 'g' || ch == 'G') {
  410.                 if (expt <= -4 || expt > prec)
  411.                     ch = (ch == 'g') ? 'e' : 'E';
  412.                 else
  413.                     ch = 'g';
  414.             } 
  415.             if (ch <= 'e') {    /* 'e' or 'E' fmt */
  416.                 --expt;
  417.                 expsize = exponent(expstr, expt, ch);
  418.                 size = expsize + ndig;
  419.                 if (ndig > 1 || flags & ALT)
  420.                     ++size;
  421.             } else if (ch == 'f') {        /* f fmt */
  422.                 if (expt > 0) {
  423.                     size = expt;
  424.                     if (prec || flags & ALT)
  425.                         size += prec + 1;
  426.                 } else    /* "0.X" */
  427.                     size = prec + 2;
  428.             } else if (expt >= ndig) {    /* fixed g fmt */
  429.                 size = expt;
  430.                 if (flags & ALT)
  431.                     ++size;
  432.             } else
  433.                 size = ndig + (expt > 0 ?
  434.                     1 : 2 - expt);
  435.  
  436.             if (softsign)
  437.                 sign = '-';
  438.             break;
  439. #endif /* FLOATING_POINT */
  440.         case 'n':
  441.             if (flags & QUADINT)
  442.                 *va_arg(ap, quad_t *) = ret;
  443.             else if (flags & LONGINT)
  444.                 *va_arg(ap, long *) = ret;
  445.             else if (flags & SHORTINT)
  446.                 *va_arg(ap, short *) = ret;
  447.             else
  448.                 *va_arg(ap, int *) = ret;
  449.             continue;    /* no output */
  450.         case 'O':
  451.             flags |= LONGINT;
  452.             /*FALLTHROUGH*/
  453.         case 'o':
  454.             _uquad = UARG();
  455.             base = OCT;
  456.             goto nosign;
  457.         case 'p':
  458.             /*
  459.              * ``The argument shall be a pointer to void.  The
  460.              * value of the pointer is converted to a sequence
  461.              * of printable characters, in an implementation-
  462.              * defined manner.''
  463.              *    -- ANSI X3J11
  464.              */
  465.             /* NOSTRICT */
  466.             _uquad = (u_quad_t)va_arg(ap, void *);
  467.             base = HEX;
  468.             xdigs = "0123456789abcdef";
  469.             flags |= HEXPREFIX;
  470.             ch = 'x';
  471.             goto nosign;
  472.         case 's':
  473.             if ((cp = va_arg(ap, char *)) == NULL)
  474.                 cp = "(null)";
  475.             if (prec >= 0) {
  476.                 /*
  477.                  * can't use strlen; can only look for the
  478.                  * NUL in the first `prec' characters, and
  479.                  * strlen() will go further.
  480.                  */
  481.                 char *p = memchr(cp, 0, prec);
  482.  
  483.                 if (p != NULL) {
  484.                     size = p - cp;
  485.                     if (size > prec)
  486.                         size = prec;
  487.                 } else
  488.                     size = prec;
  489.             } else
  490.                 size = strlen(cp);
  491.             sign = '\0';
  492.             break;
  493.         case 'U':
  494.             flags |= LONGINT;
  495.             /*FALLTHROUGH*/
  496.         case 'u':
  497.             _uquad = UARG();
  498.             base = DEC;
  499.             goto nosign;
  500.         case 'X':
  501.             xdigs = "0123456789ABCDEF";
  502.             goto hex;
  503.         case 'x':
  504.             xdigs = "0123456789abcdef";
  505. hex:            _uquad = UARG();
  506.             base = HEX;
  507.             /* leading 0x/X only if non-zero */
  508.             if (flags & ALT && _uquad != 0)
  509.                 flags |= HEXPREFIX;
  510.  
  511.             /* unsigned conversions */
  512. nosign:            sign = '\0';
  513.             /*
  514.              * ``... diouXx conversions ... if a precision is
  515.              * specified, the 0 flag will be ignored.''
  516.              *    -- ANSI X3J11
  517.              */
  518. number:            if ((dprec = prec) >= 0)
  519.                 flags &= ~ZEROPAD;
  520.  
  521.             /*
  522.              * ``The result of converting a zero value with an
  523.              * explicit precision of zero is no characters.''
  524.              *    -- ANSI X3J11
  525.              */
  526.             cp = buf + BUF;
  527.             if (_uquad != 0 || prec != 0) {
  528.                 /*
  529.                  * Unsigned mod is hard, and unsigned mod
  530.                  * by a constant is easier than that by
  531.                  * a variable; hence this switch.
  532.                  */
  533.                 switch (base) {
  534.                 case OCT:
  535.                     do {
  536.                         *--cp = to_char(_uquad & 7);
  537.                         _uquad >>= 3;
  538.                     } while (_uquad);
  539.                     /* handle octal leading 0 */
  540.                     if (flags & ALT && *cp != '0')
  541.                         *--cp = '0';
  542.                     break;
  543.  
  544.                 case DEC:
  545.                     /* many numbers are 1 digit */
  546.                     while (_uquad >= 10) {
  547.                         *--cp = to_char(_uquad % 10);
  548.                         _uquad /= 10;
  549.                     }
  550.                     *--cp = to_char(_uquad);
  551.                     break;
  552.  
  553.                 case HEX:
  554.                     do {
  555.                         *--cp = xdigs[_uquad & 15];
  556.                         _uquad >>= 4;
  557.                     } while (_uquad);
  558.                     break;
  559.  
  560.                 default:
  561.                     cp = "bug in vfprintf: bad base";
  562.                     size = strlen(cp);
  563.                     goto skipsize;
  564.                 }
  565.             }
  566.             size = buf + BUF - cp;
  567.         skipsize:
  568.             break;
  569.         default:    /* "%?" prints ?, unless ? is NUL */
  570.             if (ch == '\0')
  571.                 goto done;
  572.             /* pretend it was %c with argument ch */
  573.             cp = buf;
  574.             *cp = ch;
  575.             size = 1;
  576.             sign = '\0';
  577.             break;
  578.         }
  579.  
  580.         /*
  581.          * All reasonable formats wind up here.  At this point, `cp'
  582.          * points to a string which (if not flags&LADJUST) should be
  583.          * padded out to `width' places.  If flags&ZEROPAD, it should
  584.          * first be prefixed by any sign or other prefix; otherwise,
  585.          * it should be blank padded before the prefix is emitted.
  586.          * After any left-hand padding and prefixing, emit zeroes
  587.          * required by a decimal [diouxX] precision, then print the
  588.          * string proper, then emit zeroes required by any leftover
  589.          * floating precision; finally, if LADJUST, pad with blanks.
  590.          *
  591.          * Compute actual size, so we know how much to pad.
  592.          * fieldsz excludes decimal prec; realsz includes it.
  593.          */
  594.         fieldsz = size;
  595.         if (sign)
  596.             fieldsz++;
  597.         else if (flags & HEXPREFIX)
  598.             fieldsz += 2;
  599.         realsz = dprec > fieldsz ? dprec : fieldsz;
  600.  
  601.         /* right-adjusting blank padding */
  602.         if ((flags & (LADJUST|ZEROPAD)) == 0)
  603.             PAD(width - realsz, blanks);
  604.  
  605.         /* prefix */
  606.         if (sign) {
  607.             PRINT(&sign, 1);
  608.         } else if (flags & HEXPREFIX) {
  609.             ox[0] = '0';
  610.             ox[1] = ch;
  611.             PRINT(ox, 2);
  612.         }
  613.  
  614.         /* right-adjusting zero padding */
  615.         if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  616.             PAD(width - realsz, zeroes);
  617.  
  618.         /* leading zeroes from decimal precision */
  619.         PAD(dprec - fieldsz, zeroes);
  620.  
  621.         /* the string or number proper */
  622. #ifdef FLOATING_POINT
  623.         if ((flags & FPT) == 0) {
  624.             PRINT(cp, size);
  625.         } else {    /* glue together f_p fragments */
  626.             if (ch >= 'f') {    /* 'f' or 'g' */
  627.                 if (_double == 0) {
  628.                 /* kludge for __dtoa irregularity */
  629.                     if (prec == 0 ||
  630.                         (flags & ALT) == 0) {
  631.                         PRINT("0", 1);
  632.                     } else {
  633.                         PRINT("0.", 2);
  634.                         PAD(ndig - 1, zeroes);
  635.                     }
  636.                 } else if (expt <= 0) {
  637.                     PRINT("0.", 2);
  638.                     PAD(-expt, zeroes);
  639.                     PRINT(cp, ndig);
  640.                 } else if (expt >= ndig) {
  641.                     PRINT(cp, ndig);
  642.                     PAD(expt - ndig, zeroes);
  643.                     if (flags & ALT)
  644.                         PRINT(".", 1);
  645.                 } else {
  646.                     PRINT(cp, expt);
  647.                     cp += expt;
  648.                     PRINT(".", 1);
  649.                     PRINT(cp, ndig-expt);
  650.                 }
  651.             } else {    /* 'e' or 'E' */
  652.                 if (ndig > 1 || flags & ALT) {
  653.                     ox[0] = *cp++;
  654.                     ox[1] = '.';
  655.                     PRINT(ox, 2);
  656.                     if (_double || flags & ALT == 0) {
  657.                         PRINT(cp, ndig-1);
  658.                     } else    /* 0.[0..] */
  659.                         /* __dtoa irregularity */
  660.                         PAD(ndig - 1, zeroes);
  661.                 } else    /* XeYYY */
  662.                     PRINT(cp, 1);
  663.                 PRINT(expstr, expsize);
  664.             }
  665.         }
  666. #else
  667.         PRINT(cp, size);
  668. #endif
  669.         /* left-adjusting padding (always blank) */
  670.         if (flags & LADJUST)
  671.             PAD(width - realsz, blanks);
  672.  
  673.         /* finally, adjust ret */
  674.         ret += width > realsz ? width : realsz;
  675.  
  676.         FLUSH();    /* copy out the I/O vectors */
  677.     }
  678. done:
  679.     FLUSH();
  680. error:
  681.     return (__sferror(fp) ? EOF : ret);
  682.     /* NOTREACHED */
  683. }
  684.  
  685. #ifdef FLOATING_POINT
  686.  
  687. extern char *__dtoa __P((double, int, int, int *, int *, char **));
  688.  
  689. static char *
  690. cvt(value, ndigits, flags, sign, decpt, ch, length)
  691.     double value;
  692.     int ndigits, flags, *decpt, ch, *length;
  693.     char *sign;
  694. {
  695.     int mode, dsgn;
  696.     char *digits, *bp, *rve;
  697.  
  698.     if (ch == 'f')
  699.         mode = 3;
  700.     else {
  701.         mode = 2;
  702.     }
  703.     if (value < 0) {
  704.         value = -value;
  705.         *sign = '-';
  706.     } else
  707.         *sign = '\000';
  708.     digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
  709.     if (flags & ALT) {    /* Print trailing zeros */
  710.         bp = digits + ndigits;
  711.         if (ch == 'f') {
  712.             if (*digits == '0' && value)
  713.                 *decpt = -ndigits + 1;
  714.             bp += *decpt;
  715.         }
  716.         if (value == 0)    /* kludge for __dtoa irregularity */
  717.             rve = bp;
  718.         while (rve < bp)
  719.             *rve++ = '0';
  720.     }
  721.     *length = rve - digits;
  722.     return (digits);
  723. }
  724.  
  725. static int
  726. exponent(p0, exp, fmtch)
  727.     char *p0;
  728.     int exp, fmtch;
  729. {
  730.     register char *p, *t;
  731.     char expbuf[MAXEXP];
  732.  
  733.     p = p0;
  734.     *p++ = fmtch;
  735.     if (exp < 0) {
  736.         exp = -exp;
  737.         *p++ = '-';
  738.     }
  739.     else
  740.         *p++ = '+';
  741.     t = expbuf + MAXEXP;
  742.     if (exp > 9) {
  743.         do {
  744.             *--t = to_char(exp % 10);
  745.         } while ((exp /= 10) > 9);
  746.         *--t = to_char(exp);
  747.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  748.     }
  749.     else {
  750.         *p++ = '0';
  751.         *p++ = to_char(exp);
  752.     }
  753.     return (p - p0);
  754. }
  755. #endif /* FLOATING_POINT */
  756.