home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / progc / djlsr106.arj / SBUFVFOR.CC < prev    next >
C/C++ Source or Header  |  1992-03-29  |  20KB  |  822 lines

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