home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / zip / mint / mntlib16.lzh / MNTLIB16 / DOPRNT.C < prev    next >
C/C++ Source or Header  |  1993-08-03  |  18KB  |  723 lines

  1. /*
  2.  * Copyright (c) 1988 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. /*
  19.  * minorly customized for gcc lib
  20.  *    ++jrb
  21.  */
  22.  
  23. #ifdef LIBC_SCCS
  24. static char sccsid[] = "@(#)doprnt.c    5.37 (Berkeley) 3/26/89";
  25. #endif /* LIBC_SCCS */
  26.  
  27. #include <sys/types.h>
  28. #include <stdarg.h>
  29. #include <stdio.h>
  30. #include <ctype.h>
  31. #include <string.h>
  32. #include <limits.h>
  33. #include <math.h>
  34.  
  35. #ifndef __GNUC__    /* gcc lib has these typedefs in sys/types.h */
  36. typedef unsigned char u_char;
  37. typedef unsigned long u_long;
  38. #endif
  39.  
  40. /* 11-bit exponent (VAX G floating point) is 308 decimal digits */
  41. #define    MAXEXP        308
  42. /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
  43. #define    MAXFRACT    39
  44.  
  45. #define    DEFPREC        6
  46.  
  47. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  48.  
  49. #define    PUTC(ch)     if( fputc(ch, fp) == EOF ) return EOF;
  50.  
  51. #define ARG(basetype) \
  52.     _ulong = flags&LONGINT ? va_arg(argp, long basetype) : \
  53.         flags&SHORTINT ? (short basetype)va_arg(argp, short) : \
  54.         va_arg(argp, int)
  55.  
  56. #define TEN_MUL(X)    ((((X) << 2) + (X)) << 1)
  57.  
  58. #define    todigit(c)    ((c) - '0')
  59. #define    tochar(n)    ((n) + '0')
  60.  
  61. #define    LONGINT        0x01        /* long integer */
  62. #define    LONGDBL        0x02        /* long double; unimplemented */
  63. #define    SHORTINT    0x04        /* short integer */
  64. #define    ALT        0x08        /* alternate form */
  65. #define    LADJUST        0x10        /* left adjustment */
  66. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  67. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  68.  
  69. #ifndef __NO_FLOAT__
  70. #define __FLOATS__ 1
  71. #endif
  72.  
  73. #ifdef __FLOATS__
  74. static char *exponent    __PROTO((char *, int, int));
  75. static char *round    __PROTO((double, int *, char *, char *, int, char *));
  76. static int  cvt        __PROTO((double, int, int, char *, int, char *, char *));
  77. #endif
  78.  
  79. #ifdef __GNUC__
  80. #define _ICONV(NUMBER, BASE, BUF)                 \
  81. {                                \
  82.     short i;                            \
  83.     if(NUMBER <= 65535L)                    \
  84.     {                                \
  85.     do                             \
  86.     {                            \
  87.         __asm__ volatile("  \
  88.          divu    %3,%2;  \
  89.          swap    %0;     \
  90.          movw    %0,%1;  \
  91.          clrw    %0;     \
  92.                 swap    %0"                    \
  93.              : "=d"((long)NUMBER), "=g"(i)            \
  94.          : "0"((long)NUMBER), "g"((short)BASE));    \
  95.         *--BUF = digs[i];                    \
  96.     } while(NUMBER);                    \
  97.     }                                \
  98.     else                            \
  99.     {                                \
  100.     extern unsigned long __udivsi3(long, long); /* quot = d0, rem = d1 */     \
  101.     do                             \
  102.     {                            \
  103.         __asm__ volatile("        \
  104.          movl    %3,sp@-;      \
  105.          movl    %2,sp@-;      \
  106.          jsr    ___udivsi3;    \
  107.          movl    d0,%0;        \
  108.          movw    d1,%1;        \
  109.          addqw    #8,sp"                    \
  110.              : "=g"((long)NUMBER), "=g"(i)            \
  111.          : "0"((long)NUMBER), "g"((long)BASE)        \
  112.              : "d0", "d1", "a0", "a1");            \
  113.         *--BUF = digs[i];                    \
  114.     } while(NUMBER);                    \
  115.     }                                \
  116. }
  117. #endif /* __GNUC__ */
  118.  
  119.  
  120. int _doprnt(fp, fmt0, argp)
  121.     register FILE *fp;
  122.     const char *fmt0;
  123.     va_list argp;
  124. {
  125.     register const u_char *fmt; /* format string */
  126.     register int ch;    /* character from fmt */
  127.     register int cnt;    /* return value accumulator */
  128.     register int n;        /* random handy integer */
  129.     register char *t;    /* buffer pointer */
  130.     u_long _ulong;        /* integer arguments %[diouxX] */
  131.     short base;        /* base for [diouxX] conversion */
  132.     short dprec;        /* decimal precision in [diouxX] */
  133.     short fieldsz;        /* field size expanded by sign, etc */
  134.     short flags;        /* flags as above */
  135.     short fpprec;        /* `extra' floating precision in [eEfgG] */
  136.     short prec;        /* precision from format (%.3d), or -1 */
  137.     short realsz;        /* field size expanded by decimal precision */
  138.     short size;        /* size of converted field or string */
  139.     short width;        /* width from format (%8d), or 0 */
  140.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  141.     char *digs;        /* digits for [diouxX] conversion */
  142.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  143. #ifdef __FLOATS__
  144.     double _double;        /* double precision arguments %[eEfgG] */
  145.     char softsign;        /* temporary negative sign for floats */
  146. #endif
  147.     fmt = (const u_char *) fmt0;
  148.     digs = "0123456789abcdef";
  149.     for (cnt = 0;; ++fmt) {
  150.         if (!(ch = *fmt))
  151.             return (cnt);
  152.         if (ch != '%') {
  153.             PUTC(ch);
  154.             cnt++;
  155.             continue;
  156.         }
  157.         flags = 0; dprec = 0; fpprec = 0; width = 0;
  158.         prec = -1;
  159.         sign = '\0';
  160.  
  161. rflag:        switch (*++fmt) {
  162.         case ' ':
  163.             /*
  164.              * ``If the space and + flags both appear, the space
  165.              * flag will be ignored.''
  166.              *    -- ANSI X3J11
  167.              */
  168.             if (!sign)
  169.                 sign = ' ';
  170.             goto rflag;
  171.         case '#':
  172.             flags |= ALT;
  173.             goto rflag;
  174.         case '*':
  175.             /*
  176.              * ``A negative field width argument is taken as a
  177.              * - flag followed by a  positive field width.''
  178.              *    -- ANSI X3J11
  179.              * They don't exclude field widths read from args.
  180.              */
  181.             if ((width = (short)(va_arg(argp, int))) >= 0)
  182.                 goto rflag;
  183.             width = -width;
  184.             /* FALLTHROUGH */
  185.         case '-':
  186.             flags |= LADJUST;
  187.             goto rflag;
  188.         case '+':
  189.             sign = '+';
  190.             goto rflag;
  191.         case '.':
  192.             if (*++fmt == '*')
  193.                 n = va_arg(argp, int);
  194.             else {
  195.                 n = 0;
  196.                 while (isascii(*fmt) && isdigit(*fmt))
  197.                     n = TEN_MUL(n) + todigit(*fmt++);
  198.                 --fmt;
  199.             }
  200.             prec = n < 0 ? -1 : n;
  201.             goto rflag;
  202.         case '0':
  203.             /*
  204.              * ``Note that 0 is taken as a flag, not as the
  205.              * beginning of a field width.''
  206.              *    -- ANSI X3J11
  207.              */
  208.             flags |= ZEROPAD;
  209.             goto rflag;
  210.         case '1': case '2': case '3': case '4':
  211.         case '5': case '6': case '7': case '8': case '9':
  212.             n = 0;
  213.             do {
  214.                 n = TEN_MUL(n) + todigit(*fmt);
  215.             } while (isascii(*++fmt) && isdigit(*fmt));
  216.             width = n;
  217.             --fmt;
  218.             goto rflag;
  219.         case 'L':
  220.             flags |= LONGDBL;
  221.             goto rflag;
  222.         case 'h':
  223.             flags |= SHORTINT;
  224.             goto rflag;
  225.         case 'l':
  226.             flags |= LONGINT;
  227.             goto rflag;
  228.         case 'c':
  229.             *(t = buf) = va_arg(argp, int);
  230.             size = 1;
  231.             sign = '\0';
  232.             goto pforw;
  233.         case 'D':
  234.             flags |= LONGINT;
  235.             /*FALLTHROUGH*/
  236.         case 'd':
  237.         case 'i':
  238.             ARG(int);
  239.             if ((long)_ulong < 0) {
  240.                 _ulong = -_ulong;
  241.                 sign = '-';
  242.             }
  243.             base = 10;
  244.             goto number;
  245. #ifdef __FLOATS__
  246.         case 'e':
  247.         case 'E':
  248.         case 'f':
  249.         case 'g':
  250.         case 'G':
  251.             _double = va_arg(argp, double);
  252.             /*
  253.              * don't do unrealistic precision; just pad it with
  254.              * zeroes later, so buffer size stays rational.
  255.              */
  256.             if (prec > MAXFRACT) {
  257.                 if (*fmt != 'g' && *fmt != 'G' || (flags&ALT))
  258.                     fpprec = prec - MAXFRACT;
  259.                 prec = MAXFRACT;
  260.             }
  261.             else if (prec == -1)
  262.                 prec = DEFPREC;
  263.             /*
  264.              * softsign avoids negative 0 if _double is < 0 and
  265.              * no significant digits will be shown
  266.              */
  267.             if (_double < 0) {
  268.                 softsign = '-';
  269.                 _double = -_double;
  270.             }
  271.             else
  272.                 softsign = 0;
  273.             /*
  274.              * cvt may have to round up past the "start" of the
  275.              * buffer, i.e. ``intf("%.2f", (double)9.999);'';
  276.              * if the first char isn't NULL, it did.
  277.              */
  278.             *buf = (char)NULL;
  279.             size = cvt(_double, (int)prec, (int)flags, &softsign,
  280.                    *fmt, buf, buf + (int)sizeof(buf)); 
  281.             if (softsign)
  282.                 sign = '-';
  283.             t = *buf ? buf : buf + 1;
  284.             goto pforw;
  285. #endif /* __FLOATS__ */
  286.         case 'n':
  287.             if (flags & LONGINT)
  288.                 *va_arg(argp, long *) = cnt;
  289.             else if (flags & SHORTINT)
  290.                 *va_arg(argp, short *) = cnt;
  291.             else
  292.                 *va_arg(argp, int *) = cnt;
  293.             break;
  294.         case 'O':
  295.             flags |= LONGINT;
  296.             /*FALLTHROUGH*/
  297.         case 'o':
  298.             ARG(unsigned);
  299.             base = 8;
  300.             goto nosign;
  301.         case 'p':
  302.             /*
  303.              * ``The argument shall be a pointer to void.  The
  304.              * value of the pointer is converted to a sequence
  305.              * of printable characters, in an implementation-
  306.              * defined manner.''
  307.              *    -- ANSI X3J11
  308.              */
  309.             /* NOSTRICT */
  310.             _ulong = (u_long)va_arg(argp, void *);
  311.             base = 16;
  312.             goto nosign;
  313.         case 's':
  314.             if (!(t = va_arg(argp, char *)))
  315.                 t = "(null)";
  316.             if (prec >= 0) {
  317.                 /*
  318.                  * can't use strlen; can only look for the
  319.                  * NUL in the first `prec' characters, and
  320.                  * strlen() will go further.
  321.                  */
  322. #ifdef __GNUC__
  323.                 char *p;
  324.                 void *memchr(const void *, int, size_t);
  325. #else
  326.                 char *p, *memchr();
  327. #endif
  328.  
  329.                 if (p = (char *)memchr(t, 0, (size_t)prec)) {
  330.                     size = p - t;
  331.                     if (size > prec)
  332.                         size = prec;
  333.                 } else
  334.                     size = prec;
  335.             } else
  336.                 size = (int)strlen(t);
  337.             sign = '\0';
  338.             goto pforw;
  339.         case 'U':
  340.             flags |= LONGINT;
  341.             /*FALLTHROUGH*/
  342.         case 'u':
  343.             ARG(unsigned);
  344.             base = 10;
  345.             goto nosign;
  346.         case 'X':
  347.             digs = "0123456789ABCDEF";
  348.             /* FALLTHROUGH */
  349.         case 'x':
  350.             ARG(unsigned);
  351.             base = 16;
  352.             /* leading 0x/X only if non-zero */
  353.             if (flags & ALT && _ulong != 0)
  354.                 flags |= HEXPREFIX;
  355.  
  356.             /* unsigned conversions */
  357. nosign:            sign = '\0';
  358.             /*
  359.              * ``... diouXx conversions ... if a precision is
  360.              * specified, the 0 flag will be ignored.''
  361.              *    -- ANSI X3J11
  362.              */
  363. number:            if ((dprec = prec) >= 0)
  364.                 flags &= ~ZEROPAD;
  365.  
  366.             /*
  367.              * ``The result of converting a zero value with an
  368.              * explicit precision of zero is no characters.''
  369.              *    -- ANSI X3J11
  370.              */
  371.             t = buf + BUF;
  372.             if (_ulong != 0 || prec != 0) {
  373. #ifndef __GNUC__
  374.                 do {
  375.                     *--t = digs[_ulong % base];
  376.                     _ulong /= base;
  377.                 } while (_ulong);
  378. #else
  379.                 _ICONV(_ulong, base, t);
  380. #endif                
  381.                 digs = "0123456789abcdef";
  382.                 if (flags & ALT && base == 8 && *t != '0')
  383.                     *--t = '0'; /* octal leading 0 */
  384.             }
  385.             size = buf + BUF - t;
  386.  
  387. pforw:
  388.             /*
  389.              * All reasonable formats wind up here.  At this point,
  390.              * `t' points to a string which (if not flags&LADJUST)
  391.              * should be padded out to `width' places.  If
  392.              * flags&ZEROPAD, it should first be prefixed by any
  393.              * sign or other prefix; otherwise, it should be blank
  394.              * padded before the prefix is emitted.  After any
  395.              * left-hand padding and prefixing, emit zeroes
  396.              * required by a decimal [diouxX] precision, then print
  397.              * the string proper, then emit zeroes required by any
  398.              * leftover floating precision; finally, if LADJUST,
  399.              * pad with blanks.
  400.              */
  401.  
  402.             /*
  403.              * compute actual size, so we know how much to pad
  404.              * fieldsz excludes decimal prec; realsz includes it
  405.              */
  406.             fieldsz = size + fpprec;
  407.             if (sign)
  408.                 fieldsz++;
  409.             if (flags & HEXPREFIX)
  410.                 fieldsz += 2;
  411.             realsz = dprec > fieldsz ? dprec : fieldsz;
  412.  
  413.             /* right-adjusting blank padding */
  414.             if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
  415.                 for (n = realsz; n < width; n++)
  416.                     PUTC(' ');
  417.             /* prefix */
  418.             if (sign)
  419.                 PUTC(sign);
  420.             if (flags & HEXPREFIX) {
  421.                 PUTC('0');
  422.                 PUTC((char)*fmt);
  423.             }
  424.             /* right-adjusting zero padding */
  425.             if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  426.                 for (n = realsz; n < width; n++)
  427.                     PUTC('0');
  428.             /* leading zeroes from decimal precision */
  429.             for (n = fieldsz; n < dprec; n++)
  430.                 PUTC('0');
  431.  
  432.             /* the string or number proper */
  433.             for (n = size; --n >= 0; )
  434.                 PUTC(*t++);
  435.             /* trailing f.p. zeroes */
  436.             while (--fpprec >= 0)
  437.                 PUTC('0');
  438.             /* left-adjusting padding (always blank) */
  439.             if (flags & LADJUST)
  440.                 for (n = realsz; n < width; n++)
  441.                     PUTC(' ');
  442.             /* finally, adjust cnt */
  443.             cnt += width > realsz ? width : realsz;
  444.             break;
  445.         case '\0':    /* "%?" prints ?, unless ? is NULL */
  446.             return (cnt);
  447.         default:
  448.             PUTC((char)*fmt);
  449.             cnt++;
  450.         }
  451.     }
  452.     /* NOTREACHED */
  453. }
  454.  
  455. #ifdef __FLOATS__
  456. static int
  457. cvt(number,prec,flags, signp, fmtch, startp, endp)
  458.     double number;
  459.     register int prec;
  460.     int flags;
  461.     int fmtch;
  462.     char *signp, *startp, *endp;
  463. {
  464.     register char *p, *t;
  465.     register double fract;
  466.     int dotrim, expcnt, gformat;
  467.     double integer, tmp;
  468.     char *exponent __PROTO((char *, int, int)),
  469.          *round __PROTO((double, int *, char *, char *, int, char *));
  470.  
  471.     dotrim = expcnt = gformat = 0;
  472.     fract = modf(number, &integer);
  473.  
  474.     /* get an extra slot for rounding. */
  475.     t = ++startp;
  476.  
  477.     /*
  478.      * get integer portion of number; put into the end of the buffer; the
  479.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  480.      */
  481.     for (p = endp - 1; integer; ++expcnt) {
  482.         tmp = modf(integer / 10, &integer);
  483.         *p-- = tochar((int)((tmp + .01) * 10));
  484.     }
  485.     switch(fmtch) {
  486.     case 'f':
  487.         /* reverse integer into beginning of buffer */
  488.         if (expcnt)
  489.             for (; ++p < endp; *t++ = *p);
  490.         else
  491.             *t++ = '0';
  492.         /*
  493.          * if precision required or alternate flag set, add in a
  494.          * decimal point.
  495.          */
  496.         if (prec || flags&ALT)
  497.             *t++ = '.';
  498.         /* if requires more precision and some fraction left */
  499.         if (fract) {
  500.             if (prec)
  501.                 do {
  502.                     fract = modf(fract * 10, &tmp);
  503.                     *t++ = tochar((int)tmp);
  504.                 } while (--prec && fract);
  505.             if (fract)
  506.                 startp = round(fract, (int *)NULL, startp,
  507.                     t - 1, (char)0, signp);
  508.         }
  509.         for (; prec--; *t++ = '0');
  510.         break;
  511.     case 'e':
  512.     case 'E':
  513. eformat:    if (expcnt) {
  514.             *t++ = *++p;
  515.             if (prec || flags&ALT)
  516.                 *t++ = '.';
  517.             /* if requires more precision and some integer left */
  518.             for (; prec && ++p < endp; --prec)
  519.                 *t++ = *p;
  520.             /*
  521.              * if done precision and more of the integer component,
  522.              * round using it; adjust fract so we don't re-round
  523.              * later.
  524.              */
  525.             if (!prec && ++p < endp) {
  526.                 fract = 0;
  527.                 startp = round((double)0, &expcnt, startp,
  528.                     t - 1, *p, signp);
  529.             }
  530.             /* adjust expcnt for digit in front of decimal */
  531.             --expcnt;
  532.         }
  533.         /* until first fractional digit, decrement exponent */
  534.         else if (fract) {
  535.             /* adjust expcnt for digit in front of decimal */
  536.             for (expcnt = -1;; --expcnt) {
  537.                 fract = modf(fract * 10, &tmp);
  538.                 if (tmp)
  539.                     break;
  540.             }
  541.             *t++ = tochar((int)tmp);
  542.             if (prec || flags&ALT)
  543.                 *t++ = '.';
  544.         }
  545.         else {
  546.             *t++ = '0';
  547.             if (prec || flags&ALT)
  548.                 *t++ = '.';
  549.         }
  550.         /* if requires more precision and some fraction left */
  551.         if (fract) {
  552.             if (prec)
  553.                 do {
  554.                     fract = modf(fract * 10, &tmp);
  555.                     *t++ = tochar((int)tmp);
  556.                 } while (--prec && fract);
  557.             if (fract)
  558.                 startp = round(fract, &expcnt, startp,
  559.                     t - 1, (char)0, signp);
  560.         }
  561.         /* if requires more precision */
  562.         for (; prec--; *t++ = '0');
  563.  
  564.         /* unless alternate flag, trim any g/G format trailing 0's */
  565.         if (gformat && !(flags&ALT)) {
  566.             while (t > startp && *--t == '0');
  567.             if (*t == '.')
  568.                 --t;
  569.             ++t;
  570.         }
  571.         t = exponent(t, expcnt, fmtch);
  572.         break;
  573.     case 'g':
  574.     case 'G':
  575.         /* a precision of 0 is treated as a precision of 1. */
  576.         if (!prec)
  577.             ++prec;
  578.         /*
  579.          * ``The style used depends on the value converted; style e
  580.          * will be used only if the exponent resulting from the
  581.          * conversion is less than -4 or greater than the precision.''
  582.          *    -- ANSI X3J11
  583.          */
  584.         if (expcnt > prec || !expcnt && fract && fract < .0001) {
  585.             /*
  586.              * g/G format counts "significant digits, not digits of
  587.              * precision; for the e/E format, this just causes an
  588.              * off-by-one problem, i.e. g/G considers the digit
  589.              * before the decimal point significant and e/E doesn't
  590.              * count it as precision.
  591.              */
  592.             --prec;
  593.             fmtch -= 2;        /* G->E, g->e */
  594.             gformat = 1;
  595.             goto eformat;
  596.         }
  597.         /*
  598.          * reverse integer into beginning of buffer,
  599.          * note, decrement precision
  600.          */
  601.         if (expcnt)
  602.             for (; ++p < endp; *t++ = *p, --prec);
  603.         else
  604.             *t++ = '0';
  605.         /*
  606.          * if precision required or alternate flag set, add in a
  607.          * decimal point.  If no digits yet, add in leading 0.
  608.          */
  609.         if (prec || flags&ALT) {
  610.             dotrim = 1;
  611.             *t++ = '.';
  612.         }
  613.         else
  614.             dotrim = 0;
  615.         /* if requires more precision and some fraction left */
  616.         if (fract) {
  617.             if (prec) {
  618.                 if (0 == expcnt) {
  619.                     /* if no significant digits yet */
  620.                     do {
  621.                         fract = modf(fract * 10, &tmp);
  622.                         *t++ = tochar((int)tmp);
  623.                     } while(!tmp);
  624.                 }
  625.                 while (--prec && fract) {
  626.                     fract = modf(fract * 10, &tmp);
  627.                     *t++ = tochar((int)tmp);
  628.                 }
  629.             }
  630.             if (fract)
  631.                 startp = round(fract, (int *)NULL, startp,
  632.                     t - 1, (char)0, signp);
  633.         }
  634.         /* alternate format, adds 0's for precision, else trim 0's */
  635.         if (flags&ALT)
  636.             for (; prec--; *t++ = '0');
  637.         else if (dotrim) {
  638.             while (t > startp && *--t == '0');
  639.             if (*t != '.')
  640.                 ++t;
  641.         }
  642.     }
  643.     return((int)(t - startp));
  644. }
  645.  
  646. static char *
  647. round(fract, exp, start, end, ch, signp)
  648.     double fract;
  649.     int *exp;
  650.     register char *start, *end;
  651.     int ch;
  652.     char *signp;
  653. {
  654.     double tmp;
  655.  
  656.     if (fract)
  657.         (void)modf(fract * 10, &tmp);
  658.     else
  659.         tmp = todigit(ch);
  660.     if (tmp > 4)
  661.         for (;; --end) {
  662.             if (*end == '.')
  663.                 --end;
  664.             if (++*end <= '9')
  665.                 break;
  666.             *end = '0';
  667.             if (end == start) {
  668.                 if (exp) {    /* e/E; increment exponent */
  669.                     *end = '1';
  670.                     ++*exp;
  671.                 }
  672.                 else {        /* f; add extra digit */
  673.                     *--end = '1';
  674.                     --start;
  675.                 }
  676.                 break;
  677.             }
  678.         }
  679.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  680.     else if (*signp == '-')
  681.         for (;; --end) {
  682.             if (*end == '.')
  683.                 --end;
  684.             if (*end != '0')
  685.                 break;
  686.             if (end == start)
  687.                 *signp = 0;
  688.         }
  689.     return(start);
  690. }
  691.  
  692. static char *
  693. exponent(p, exp, fmtch)
  694.     register char *p;
  695.     register int exp;
  696.     int fmtch;
  697. {
  698.     register char *t;
  699.     char expbuf[MAXEXP];
  700.  
  701.     *p++ = fmtch;
  702.     if (exp < 0) {
  703.         exp = -exp;
  704.         *p++ = '-';
  705.     }
  706.     else
  707.         *p++ = '+';
  708.     t = expbuf + MAXEXP;
  709.     if (exp > 9) {
  710.         do {
  711.             *--t = tochar(exp % 10);
  712.         } while ((exp /= 10) > 9);
  713.         *--t = tochar(exp);
  714.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  715.     }
  716.     else {
  717.         *p++ = '0';
  718.         *p++ = tochar(exp);
  719.     }
  720.     return(p);
  721. }
  722. #endif __FLOATS__
  723.