home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Portable Patmos 1.1 / patmos-src / src / vkprintf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-19  |  19.3 KB  |  841 lines  |  [TEXT/KAHL]

  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.  
  57. #undef FLOATING_POINT
  58.  
  59. /* end of configuration stuff */
  60.  
  61. #ifdef FLOATING_POINT
  62.  
  63. static double modf(double value, double *iptr)
  64.     {
  65.     long x = (int) value;
  66.     if (x >= 0)
  67.         {
  68.         if (value < (double)x) x--;
  69.         }
  70.     else
  71.         {
  72.         if (value > (double)x) x++;
  73.         }
  74.     *iptr = x;
  75.     return value - *iptr;
  76.     }
  77.  
  78. #include "floatio.h"
  79.  
  80. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  81. #define    DEFPREC        6
  82.  
  83. static int cvt();
  84.  
  85. #else /* no FLOATING_POINT */
  86.  
  87. #define    BUF        40
  88.  
  89. #endif /* FLOATING_POINT */
  90.  
  91.  
  92. /*
  93.  * Macros for converting digits to letters and vice versa
  94.  */
  95. #define    to_digit(c)    ((c) - '0')
  96. #define is_digit(c)    ((unsigned)to_digit(c) <= 9)
  97. #define    to_char(n)    ((n) + '0')
  98.  
  99. /*
  100.  * Flags used during conversion.
  101.  */
  102. #define    LONGINT        0x01        /* long integer */
  103. #define    LONGDBL        0x02        /* long double; unimplemented */
  104. #define    SHORTINT    0x04        /* short integer */
  105. #define    ALT        0x08        /* alternate form */
  106. #define    LADJUST        0x10        /* left adjustment */
  107. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  108. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  109.  
  110. int
  111. vkprintf(fp, fmt0, ap)
  112.     char *fp;
  113.     const char *fmt0;
  114. #if tahoe
  115.  register /* technically illegal, since we do not know what type va_list is */
  116. #endif
  117.     va_list ap;
  118. {
  119.     register char *fmt;    /* format string */
  120.     register int ch;    /* character from fmt */
  121.     register int n;        /* handy integer (short term usage) */
  122.     register char *cp;    /* handy char pointer (short term usage) */
  123.     register struct __siov *iovp;/* for PRINT macro */
  124.     register int flags;    /* flags as above */
  125.     int ret;        /* return value accumulator */
  126.     int width;        /* width from format (%8d), or 0 */
  127.     int prec;        /* precision from format (%.3d), or -1 */
  128.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  129. #ifdef FLOATING_POINT
  130.     char softsign;        /* temporary negative sign for floats */
  131.     double _double;        /* double precision arguments %[eEfgG] */
  132.     int fpprec;        /* `extra' floating precision in [eEfgG] */
  133. #endif
  134.     u_long _ulong;        /* integer arguments %[diouxX] */
  135.     enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
  136.     int dprec;        /* a copy of prec if [diouxX], 0 otherwise */
  137.     int fieldsz;        /* field size expanded by sign, etc */
  138.     int realsz;        /* field size expanded by dprec */
  139.     int size;        /* size of converted field or string */
  140.     char *xdigs;        /* digits for [xX] conversion */
  141. #define NIOV 8
  142.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  143.     char ox[2];        /* space for 0x hex-prefix */
  144.  
  145.     /*
  146.      * Choose PADSIZE to trade efficiency vs size.  If larger
  147.      * printf fields occur frequently, increase PADSIZE (and make
  148.      * the initialisers below longer).
  149.      */
  150. #define    PADSIZE    16        /* pad chunk size */
  151.     static char blanks[PADSIZE] =
  152.      {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
  153.     static char zeroes[PADSIZE] =
  154.      {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
  155.  
  156.     /*
  157.      * BEWARE, these `goto error' on error, and PAD uses `n'.
  158.      */
  159. #define    PRINT(ptr, len) { memcpy(fp, ptr, len); fp += len; }
  160.  
  161. #define    PAD(howmany, with) { \
  162.     if ((n = (howmany)) > 0) { \
  163.         while (n > PADSIZE) { \
  164.             PRINT(with, PADSIZE); \
  165.             n -= PADSIZE; \
  166.         } \
  167.         PRINT(with, n); \
  168.     } \
  169. }
  170. #define    FLUSH() *fp = 0
  171.  
  172.     /*
  173.      * To extend shorts properly, we need both signed and unsigned
  174.      * argument extraction methods.
  175.      */
  176. #define    SARG() \
  177.     (flags&LONGINT ? va_arg(ap, long) : \
  178.         flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
  179.         (long)va_arg(ap, int))
  180. #define    UARG() \
  181.     (flags&LONGINT ? va_arg(ap, u_long) : \
  182.         flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
  183.         (u_long)va_arg(ap, u_int))
  184.  
  185.     fmt = (char *)fmt0;
  186.     ret = 0;
  187.  
  188.     /*
  189.      * Scan the format for conversions (`%' character).
  190.      */
  191.     for (;;) {
  192.         for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
  193.             /* void */;
  194.         if ((n = fmt - cp) != 0) {
  195.             PRINT(cp, n);
  196.             ret += n;
  197.         }
  198.         if (ch == '\0')
  199.             goto done;
  200.         fmt++;        /* skip over '%' */
  201.  
  202.         flags = 0;
  203.         dprec = 0;
  204. #ifdef FLOATING_POINT
  205.         fpprec = 0;
  206. #endif
  207.         width = 0;
  208.         prec = -1;
  209.         sign = '\0';
  210.  
  211. rflag:        ch = *fmt++;
  212. reswitch:    switch (ch) {
  213.         case ' ':
  214.             /*
  215.              * ``If the space and + flags both appear, the space
  216.              * flag will be ignored.''
  217.              *    -- ANSI X3J11
  218.              */
  219.             if (!sign)
  220.                 sign = ' ';
  221.             goto rflag;
  222.         case '#':
  223.             flags |= ALT;
  224.             goto rflag;
  225.         case '*':
  226.             /*
  227.              * ``A negative field width argument is taken as a
  228.              * - flag followed by a positive field width.''
  229.              *    -- ANSI X3J11
  230.              * They don't exclude field widths read from args.
  231.              */
  232.             if ((width = va_arg(ap, int)) >= 0)
  233.                 goto rflag;
  234.             width = -width;
  235.             /* FALLTHROUGH */
  236.         case '-':
  237.             flags |= LADJUST;
  238.             goto rflag;
  239.         case '+':
  240.             sign = '+';
  241.             goto rflag;
  242.         case '.':
  243.             if ((ch = *fmt++) == '*') {
  244.                 n = va_arg(ap, int);
  245.                 prec = n < 0 ? -1 : n;
  246.                 goto rflag;
  247.             }
  248.             n = 0;
  249.             while (is_digit(ch)) {
  250.                 n = 10 * n + to_digit(ch);
  251.                 ch = *fmt++;
  252.             }
  253.             prec = n < 0 ? -1 : n;
  254.             goto reswitch;
  255.         case '0':
  256.             /*
  257.              * ``Note that 0 is taken as a flag, not as the
  258.              * beginning of a field width.''
  259.              *    -- ANSI X3J11
  260.              */
  261.             flags |= ZEROPAD;
  262.             goto rflag;
  263.         case '1': case '2': case '3': case '4':
  264.         case '5': case '6': case '7': case '8': case '9':
  265.             n = 0;
  266.             do {
  267.                 n = 10 * n + to_digit(ch);
  268.                 ch = *fmt++;
  269.             } while (is_digit(ch));
  270.             width = n;
  271.             goto reswitch;
  272. #ifdef FLOATING_POINT
  273.         case 'L':
  274.             flags |= LONGDBL;
  275.             goto rflag;
  276. #endif
  277.         case 'h':
  278.             flags |= SHORTINT;
  279.             goto rflag;
  280.         case 'l':
  281.             flags |= LONGINT;
  282.             goto rflag;
  283.         case 'c':
  284.             *(cp = buf) = va_arg(ap, int);
  285.             size = 1;
  286.             sign = '\0';
  287.             break;
  288.         case 'D':
  289.             flags |= LONGINT;
  290.             /*FALLTHROUGH*/
  291.         case 'd':
  292.         case 'i':
  293.             _ulong = SARG();
  294.             if ((long)_ulong < 0) {
  295.                 _ulong = -_ulong;
  296.                 sign = '-';
  297.             }
  298.             base = DEC;
  299.             goto number;
  300. #ifdef FLOATING_POINT
  301.         case 'e':
  302.         case 'E':
  303.         case 'f':
  304.         case 'g':
  305.         case 'G':
  306.             _double = va_arg(ap, double);
  307.             /* do this before tricky precision changes */
  308.             /*
  309.              * don't do unrealistic precision; just pad it with
  310.              * zeroes later, so buffer size stays rational.
  311.              */
  312.             if (prec > MAXFRACT) {
  313.                 if (ch != 'g' && ch != 'G' || (flags&ALT))
  314.                     fpprec = prec - MAXFRACT;
  315.                 prec = MAXFRACT;
  316.             } else if (prec == -1)
  317.                 prec = DEFPREC;
  318.             /*
  319.              * cvt may have to round up before the "start" of
  320.              * its buffer, i.e. ``intf("%.2f", (double)9.999);'';
  321.              * if the first character is still NUL, it did.
  322.              * softsign avoids negative 0 if _double < 0 but
  323.              * no significant digits will be shown.
  324.              */
  325.             cp = buf;
  326.             *cp = '\0';
  327.             size = cvt(_double, prec, flags, &softsign, ch,
  328.                 cp, buf + sizeof(buf));
  329.             if (softsign)
  330.                 sign = '-';
  331.             if (*cp == '\0')
  332.                 cp++;
  333.             break;
  334. #endif /* FLOATING_POINT */
  335.         case 'n':
  336.             if (flags & LONGINT)
  337.                 *va_arg(ap, long *) = ret;
  338.             else if (flags & SHORTINT)
  339.                 *va_arg(ap, short *) = ret;
  340.             else
  341.                 *va_arg(ap, int *) = ret;
  342.             continue;    /* no output */
  343.         case 'O':
  344.             flags |= LONGINT;
  345.             /*FALLTHROUGH*/
  346.         case 'o':
  347.             _ulong = UARG();
  348.             base = OCT;
  349.             goto nosign;
  350.         case 'p':
  351.             /*
  352.              * ``The argument shall be a pointer to void.  The
  353.              * value of the pointer is converted to a sequence
  354.              * of printable characters, in an implementation-
  355.              * defined manner.''
  356.              *    -- ANSI X3J11
  357.              */
  358.             /* NOSTRICT */
  359.             _ulong = (u_long)va_arg(ap, void *);
  360.             base = HEX;
  361.             xdigs = "0123456789abcdef";
  362.             flags |= HEXPREFIX;
  363.             ch = 'x';
  364.             goto nosign;
  365.         case 's':
  366.             if ((cp = va_arg(ap, char *)) == NULL)
  367.                 cp = "(null)";
  368.             if (prec >= 0) {
  369.                 /*
  370.                  * can't use strlen; can only look for the
  371.                  * NUL in the first `prec' characters, and
  372.                  * strlen() will go further.
  373.                  */
  374.                 char *p = memchr(cp, 0, prec);
  375.  
  376.                 if (p != NULL) {
  377.                     size = p - cp;
  378.                     if (size > prec)
  379.                         size = prec;
  380.                 } else
  381.                     size = prec;
  382.             } else
  383.                 size = strlen(cp);
  384.             sign = '\0';
  385.             break;
  386.         case 'U':
  387.             flags |= LONGINT;
  388.             /*FALLTHROUGH*/
  389.         case 'u':
  390.             _ulong = UARG();
  391.             base = DEC;
  392.             goto nosign;
  393.         case 'X':
  394.             xdigs = "0123456789ABCDEF";
  395.             goto hex;
  396.         case 'x':
  397.             xdigs = "0123456789abcdef";
  398. hex:            _ulong = UARG();
  399.             base = HEX;
  400.             /* leading 0x/X only if non-zero */
  401.             if (flags & ALT && _ulong != 0)
  402.                 flags |= HEXPREFIX;
  403.  
  404.             /* unsigned conversions */
  405. nosign:            sign = '\0';
  406.             /*
  407.              * ``... diouXx conversions ... if a precision is
  408.              * specified, the 0 flag will be ignored.''
  409.              *    -- ANSI X3J11
  410.              */
  411. number:            if ((dprec = prec) >= 0)
  412.                 flags &= ~ZEROPAD;
  413.  
  414.             /*
  415.              * ``The result of converting a zero value with an
  416.              * explicit precision of zero is no characters.''
  417.              *    -- ANSI X3J11
  418.              */
  419.             cp = buf + BUF;
  420.             if (_ulong != 0 || prec != 0) {
  421.                 /*
  422.                  * unsigned mod is hard, and unsigned mod
  423.                  * by a constant is easier than that by
  424.                  * a variable; hence this switch.
  425.                  */
  426.                 switch (base) {
  427.                 case OCT:
  428.                     do {
  429.                         *--cp = to_char(_ulong & 7);
  430.                         _ulong >>= 3;
  431.                     } while (_ulong);
  432.                     /* handle octal leading 0 */
  433.                     if (flags & ALT && *cp != '0')
  434.                         *--cp = '0';
  435.                     break;
  436.  
  437.                 case DEC:
  438.                     /* many numbers are 1 digit */
  439.                     while (_ulong >= 10) {
  440.                         *--cp = to_char(_ulong % 10);
  441.                         _ulong /= 10;
  442.                     }
  443.                     *--cp = to_char(_ulong);
  444.                     break;
  445.  
  446.                 case HEX:
  447.                     do {
  448.                         *--cp = xdigs[_ulong & 15];
  449.                         _ulong >>= 4;
  450.                     } while (_ulong);
  451.                     break;
  452.  
  453.                 default:
  454.                     cp = "bug in vfprintf: bad base";
  455.                     size = strlen(cp);
  456.                     goto skipsize;
  457.                 }
  458.             }
  459.             size = buf + BUF - cp;
  460.         skipsize:
  461.             break;
  462.         default:    /* "%?" prints ?, unless ? is NUL */
  463.             if (ch == '\0')
  464.                 goto done;
  465.             /* pretend it was %c with argument ch */
  466.             cp = buf;
  467.             *cp = ch;
  468.             size = 1;
  469.             sign = '\0';
  470.             break;
  471.         }
  472.  
  473.         /*
  474.          * All reasonable formats wind up here.  At this point,
  475.          * `cp' points to a string which (if not flags&LADJUST)
  476.          * should be padded out to `width' places.  If
  477.          * flags&ZEROPAD, it should first be prefixed by any
  478.          * sign or other prefix; otherwise, it should be blank
  479.          * padded before the prefix is emitted.  After any
  480.          * left-hand padding and prefixing, emit zeroes
  481.          * required by a decimal [diouxX] precision, then print
  482.          * the string proper, then emit zeroes required by any
  483.          * leftover floating precision; finally, if LADJUST,
  484.          * pad with blanks.
  485.          */
  486.  
  487.         /*
  488.          * compute actual size, so we know how much to pad.
  489.          * fieldsz excludes decimal prec; realsz includes it
  490.          */
  491. #ifdef FLOATING_POINT
  492.         fieldsz = size + fpprec;
  493. #else
  494.         fieldsz = size;
  495. #endif
  496.         if (sign)
  497.             fieldsz++;
  498.         else if (flags & HEXPREFIX)
  499.             fieldsz += 2;
  500.         realsz = dprec > fieldsz ? dprec : fieldsz;
  501.  
  502.         /* right-adjusting blank padding */
  503.         if ((flags & (LADJUST|ZEROPAD)) == 0)
  504.             PAD(width - realsz, blanks);
  505.  
  506.         /* prefix */
  507.         if (sign) {
  508.             PRINT(&sign, 1);
  509.         } else if (flags & HEXPREFIX) {
  510.             ox[0] = '0';
  511.             ox[1] = ch;
  512.             PRINT(ox, 2);
  513.         }
  514.  
  515.         /* right-adjusting zero padding */
  516.         if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  517.             PAD(width - realsz, zeroes);
  518.  
  519.         /* leading zeroes from decimal precision */
  520.         PAD(dprec - fieldsz, zeroes);
  521.  
  522.         /* the string or number proper */
  523.         PRINT(cp, size);
  524.  
  525. #ifdef FLOATING_POINT
  526.         /* trailing f.p. zeroes */
  527.         PAD(fpprec, zeroes);
  528. #endif
  529.  
  530.         /* left-adjusting padding (always blank) */
  531.         if (flags & LADJUST)
  532.             PAD(width - realsz, blanks);
  533.  
  534.         /* finally, adjust ret */
  535.         ret += width > realsz ? width : realsz;
  536.  
  537.         FLUSH();    /* copy out the I/O vectors */
  538.     }
  539. done:
  540.     FLUSH();
  541. error:
  542.     return (ret);
  543.     /* NOTREACHED */
  544. }
  545.  
  546. #ifdef FLOATING_POINT
  547. #include <math.h>
  548.  
  549. static char *exponent();
  550. static char *round();
  551.  
  552. static int
  553. cvt(number, prec, flags, signp, fmtch, startp, endp)
  554.     double number;
  555.     register int prec;
  556.     int flags;
  557.     char *signp;
  558.     int fmtch;
  559.     char *startp, *endp;
  560. {
  561.     register char *p, *t;
  562.     register double fract;
  563.     int dotrim, expcnt, gformat;
  564.     double integer, tmp;
  565.  
  566.     dotrim = expcnt = gformat = 0;
  567.     if (number < 0) {
  568.         number = -number;
  569.         *signp = '-';
  570.     } else
  571.         *signp = 0;
  572.  
  573.     fract = modf(number, &integer);
  574.  
  575.     /* get an extra slot for rounding. */
  576.     t = ++startp;
  577.  
  578.     /*
  579.      * get integer portion of number; put into the end of the buffer; the
  580.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  581.      */
  582.     for (p = endp - 1; integer; ++expcnt) {
  583.         tmp = modf(integer / 10, &integer);
  584.         *p-- = to_char((int)((tmp + .01) * 10));
  585.     }
  586.     switch (fmtch) {
  587.     case 'f':
  588.         /* reverse integer into beginning of buffer */
  589.         if (expcnt)
  590.             for (; ++p < endp; *t++ = *p);
  591.         else
  592.             *t++ = '0';
  593.         /*
  594.          * if precision required or alternate flag set, add in a
  595.          * decimal point.
  596.          */
  597.         if (prec || flags&ALT)
  598.             *t++ = '.';
  599.         /* if requires more precision and some fraction left */
  600.         if (fract) {
  601.             if (prec)
  602.                 do {
  603.                     fract = modf(fract * 10, &tmp);
  604.                     *t++ = to_char((int)tmp);
  605.                 } while (--prec && fract);
  606.             if (fract)
  607.                 startp = round(fract, (int *)NULL, startp,
  608.                     t - 1, (char)0, signp);
  609.         }
  610.         for (; prec--; *t++ = '0');
  611.         break;
  612.     case 'e':
  613.     case 'E':
  614. eformat:    if (expcnt) {
  615.             *t++ = *++p;
  616.             if (prec || flags&ALT)
  617.                 *t++ = '.';
  618.             /* if requires more precision and some integer left */
  619.             for (; prec && ++p < endp; --prec)
  620.                 *t++ = *p;
  621.             /*
  622.              * if done precision and more of the integer component,
  623.              * round using it; adjust fract so we don't re-round
  624.              * later.
  625.              */
  626.             if (!prec && ++p < endp) {
  627.                 fract = 0;
  628.                 startp = round((double)0, &expcnt, startp,
  629.                     t - 1, *p, signp);
  630.             }
  631.             /* adjust expcnt for digit in front of decimal */
  632.             --expcnt;
  633.         }
  634.         /* until first fractional digit, decrement exponent */
  635.         else if (fract) {
  636.             /* adjust expcnt for digit in front of decimal */
  637.             for (expcnt = -1;; --expcnt) {
  638.                 fract = modf(fract * 10, &tmp);
  639.                 if (tmp)
  640.                     break;
  641.             }
  642.             *t++ = to_char((int)tmp);
  643.             if (prec || flags&ALT)
  644.                 *t++ = '.';
  645.         }
  646.         else {
  647.             *t++ = '0';
  648.             if (prec || flags&ALT)
  649.                 *t++ = '.';
  650.         }
  651.         /* if requires more precision and some fraction left */
  652.         if (fract) {
  653.             if (prec)
  654.                 do {
  655.                     fract = modf(fract * 10, &tmp);
  656.                     *t++ = to_char((int)tmp);
  657.                 } while (--prec && fract);
  658.             if (fract)
  659.                 startp = round(fract, &expcnt, startp,
  660.                     t - 1, (char)0, signp);
  661.         }
  662.         /* if requires more precision */
  663.         for (; prec--; *t++ = '0');
  664.  
  665.         /* unless alternate flag, trim any g/G format trailing 0's */
  666.         if (gformat && !(flags&ALT)) {
  667.             while (t > startp && *--t == '0');
  668.             if (*t == '.')
  669.                 --t;
  670.             ++t;
  671.         }
  672.         t = exponent(t, expcnt, fmtch);
  673.         break;
  674.     case 'g':
  675.     case 'G':
  676.         /* a precision of 0 is treated as a precision of 1. */
  677.         if (!prec)
  678.             ++prec;
  679.         /*
  680.          * ``The style used depends on the value converted; style e
  681.          * will be used only if the exponent resulting from the
  682.          * conversion is less than -4 or greater than the precision.''
  683.          *    -- ANSI X3J11
  684.          */
  685.         if (expcnt > prec || !expcnt && fract && fract < .0001) {
  686.             /*
  687.              * g/G format counts "significant digits, not digits of
  688.              * precision; for the e/E format, this just causes an
  689.              * off-by-one problem, i.e. g/G considers the digit
  690.              * before the decimal point significant and e/E doesn't
  691.              * count it as precision.
  692.              */
  693.             --prec;
  694.             fmtch -= 2;        /* G->E, g->e */
  695.             gformat = 1;
  696.             goto eformat;
  697.         }
  698.         /*
  699.          * reverse integer into beginning of buffer,
  700.          * note, decrement precision
  701.          */
  702.         if (expcnt)
  703.             for (; ++p < endp; *t++ = *p, --prec);
  704.         else
  705.             *t++ = '0';
  706.         /*
  707.          * if precision required or alternate flag set, add in a
  708.          * decimal point.  If no digits yet, add in leading 0.
  709.          */
  710.         if (prec || flags&ALT) {
  711.             dotrim = 1;
  712.             *t++ = '.';
  713.         }
  714.         else
  715.             dotrim = 0;
  716.         /* if requires more precision and some fraction left */
  717.         if (fract) {
  718.             if (prec) {
  719.                 do {
  720.                     fract = modf(fract * 10, &tmp);
  721.                     *t++ = to_char((int)tmp);
  722.                 } while(!tmp);
  723.                 while (--prec && fract) {
  724.                     fract = modf(fract * 10, &tmp);
  725.                     *t++ = to_char((int)tmp);
  726.                 }
  727.             }
  728.             if (fract)
  729.                 startp = round(fract, (int *)NULL, startp,
  730.                     t - 1, (char)0, signp);
  731.         }
  732.         /* alternate format, adds 0's for precision, else trim 0's */
  733.         if (flags&ALT)
  734.             for (; prec--; *t++ = '0');
  735.         else if (dotrim) {
  736.             while (t > startp && *--t == '0');
  737.             if (*t != '.')
  738.                 ++t;
  739.         }
  740.     }
  741.     return (t - startp);
  742. }
  743.  
  744. static char *
  745. round(fract, exp, start, end, ch, signp)
  746.     double fract;
  747.     int *exp;
  748.     register char *start, *end;
  749.     char ch, *signp;
  750. {
  751.     double tmp;
  752.  
  753.     if (fract)
  754.         (void)modf(fract * 10, &tmp);
  755.     else
  756.         tmp = to_digit(ch);
  757.     if (tmp > 4)
  758.         for (;; --end) {
  759.             if (*end == '.')
  760.                 --end;
  761.             if (++*end <= '9')
  762.                 break;
  763.             *end = '0';
  764.             if (end == start) {
  765.                 if (exp) {    /* e/E; increment exponent */
  766.                     *end = '1';
  767.                     ++*exp;
  768.                 }
  769.                 else {        /* f; add extra digit */
  770.                 *--end = '1';
  771.                 --start;
  772.                 }
  773.                 break;
  774.             }
  775.         }
  776.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  777.     else if (*signp == '-')
  778.         for (;; --end) {
  779.             if (*end == '.')
  780.                 --end;
  781.             if (*end != '0')
  782.                 break;
  783.             if (end == start)
  784.                 *signp = 0;
  785.         }
  786.     return (start);
  787. }
  788.  
  789. static char *
  790. exponent(p, exp, fmtch)
  791.     register char *p;
  792.     register int exp;
  793.     int fmtch;
  794. {
  795.     register char *t;
  796.     char expbuf[MAXEXP];
  797.  
  798.     *p++ = fmtch;
  799.     if (exp < 0) {
  800.         exp = -exp;
  801.         *p++ = '-';
  802.     }
  803.     else
  804.         *p++ = '+';
  805.     t = expbuf + MAXEXP;
  806.     if (exp > 9) {
  807.         do {
  808.             *--t = to_char(exp % 10);
  809.         } while ((exp /= 10) > 9);
  810.         *--t = to_char(exp);
  811.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  812.     }
  813.     else {
  814.         *p++ = '0';
  815.         *p++ = to_char(exp);
  816.     }
  817.     return (p);
  818. }
  819. #endif /* FLOATING_POINT */
  820.  
  821. #if __STDC__
  822. ksprintf(char *str, char const *fmt, ...)
  823. #else
  824. ksprintf(str, fmt, va_alist)
  825.     char *str;
  826.     char *fmt;
  827.     va_dcl
  828. #endif
  829. {
  830.     int ret;
  831.     va_list ap;
  832. #if __STDC__
  833.     va_start(ap, fmt);
  834. #else
  835.     va_start(ap);
  836. #endif
  837.     ret = vkprintf(str, fmt, ap);
  838.     va_end(ap);
  839.     return (ret);
  840. }
  841.