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