home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / mntlib32.zoo / doprnt.c < prev    next >
C/C++ Source or Header  |  1993-06-17  |  26KB  |  1,143 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.  * and for the sfp004 as well as the TT's 68881
  22.  *      mjr++
  23.  * and for turbo C and the MiNT library
  24.  *     ++um,mh
  25.  * and special M68881 and sfp004 version of cvt() added that uses fmovep for
  26.  * maximum precision, no bits lost anymore!
  27.  *    ++schwab
  28.  */
  29.  
  30. #ifndef __NO_FLOAT__
  31. #if 0
  32. static unsigned long
  33.     __notanumber[2] = { 0x7fffffffL, 0xffffffffL }; /* ieee NAN */
  34. #define NAN  (*((double *)&__notanumber[0]))
  35. static unsigned long
  36.     __p_infinity[2] = { 0x7ff00000L, 0x00000000L }; /* ieee NAN */
  37. #define INF  (*((double *)&__p_infinity[0]))
  38. #endif
  39.  
  40. #define NAN_HI 0x7fffffffL
  41. #define NAN_LO 0xffffffffL
  42. #define INF_HI 0x7ff00000L
  43. #define INF_LO 0x00000000L
  44.  
  45. #endif /* __NO_FLOAT__ */
  46.  
  47. #ifdef LIBC_SCCS
  48. static char sccsid[] = "@(#)doprnt.c    5.37 (Berkeley) 3/26/89";
  49. #endif /* LIBC_SCCS */
  50.  
  51. #include <compiler.h>
  52. #ifdef __TURBOC__
  53. #include <sys\types.h>
  54. #else
  55. #include <sys/types.h>
  56. #endif
  57. #include <stdarg.h>
  58. #include <stdio.h>
  59. #include <ctype.h>
  60. #include <string.h>
  61. #include <limits.h>
  62. #include    <math.h>    /* mjr++    */
  63.  
  64. #ifndef __GNUC__    /* gcc lib has these typedefs in sys/types.h */
  65. #ifndef __MINT__    /* as does the MiNT library */
  66. typedef unsigned char u_char;
  67. typedef unsigned long u_long;
  68. #endif
  69. #endif
  70.  
  71. /* 11-bit exponent (VAX G floating point) is 308 decimal digits */
  72. #define    MAXEXP        308
  73.  
  74. /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
  75. # define    MAXFRACT    39
  76. # define    MAXEXP        308
  77.  
  78. #if defined (__M68881__) && !defined (sfp004)
  79. #  include <math-68881.h>    /* mjr: use the inline functions    */
  80. #endif    __M68881__
  81.  
  82. #define    DEFPREC        6
  83.  
  84. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  85.  
  86. #define    PUTC(ch)     if( fputc(ch, fp) == EOF ) return EOF;
  87.  
  88.  
  89. #define ARG(signtag) \
  90.     _ulong = \
  91.         flags&LONGINT ? \
  92.             (unsigned long)va_arg(argp, signtag long) : \
  93.         (flags&SHORTINT ? \
  94.             (unsigned long)(signtag short)va_arg(argp, signtag int) : \
  95.              (unsigned long)va_arg(argp, signtag int))
  96.      /* shorts are always promoted to ints; thus, it's `va_arg(... int)'
  97.       * for `flags&SHORTINT'!
  98.       */
  99.  
  100. #define TEN_MUL(X)    ((((X) << 2) + (X)) << 1)
  101.  
  102. #define    todigit(c)    ((c) - '0')
  103. #define    tochar(n)    ((n) + '0')
  104.  
  105. #define    LONGINT        0x01        /* long integer */
  106. #define    LONGDBL        0x02        /* long double; unimplemented */
  107. #define    SHORTINT    0x04        /* short integer */
  108. #define    ALT        0x08        /* alternate form */
  109. #define    LADJUST        0x10        /* left adjustment */
  110. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  111. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  112.  
  113. #ifndef __NO_FLOAT__
  114. #define __FLOATS__ 1
  115. #endif
  116.  
  117. #ifdef __FLOATS__
  118. # include    "flonum.h"
  119. #if defined (__M68881__) || defined (sfp004)
  120. static char *exponent __PROTO ((char *, int, int));
  121. static int _round __PROTO ((int, char *, char *, char *));
  122. static int cvt __PROTO ((double, int, int, char *, int, char *));
  123. #else
  124. #  if __STDC__
  125. static char *exponent(char *, int, int);
  126. static char *_round(double, int *, char *, char *, int, char *);
  127. static int  cvt(double, int, int, char *, int, char *, char *);
  128. #  else
  129. static char *exponent();
  130. static char *_round();
  131. static int  cvt();
  132. #  endif
  133. #endif /* __M68881__ */
  134. #endif
  135.  
  136. #if defined(__GNUC__) && (!defined(__NO_INLINE__))
  137. #ifdef __M68020__
  138.  
  139. #define _ICONV(NUMBER, BASE, BUF)                \
  140. {                                \
  141.   long i;                            \
  142.   do                                \
  143.     {                                \
  144.       __asm__ volatile                        \
  145.     ("divull %3,%1:%0"                    \
  146.      : "=d"((long)(NUMBER)), "=d"(i)            \
  147.      : "0"((long)(NUMBER)), "d"((long)(BASE)));        \
  148.       *--(BUF) = digs[i];                    \
  149.     }                                \
  150.   while (NUMBER);                        \
  151. }
  152.  
  153. #else /* !__M68020 */  
  154.  
  155. #define _ICONV(NUMBER, BASE, BUF)                 \
  156. {                                \
  157.                                 \
  158.     while((NUMBER) > 65535L)                    \
  159.     {                                \
  160.         extern unsigned long __udivsi3(); /* quot = d0, rem = d1 */ \
  161.         register long i __asm ("d1");                    \
  162.     __asm__ volatile("
  163.         movl    %3,sp@-;
  164.          movl    %2,sp@-;
  165.          jsr    ___udivsi3;
  166.          addqw    #8,sp;
  167.          movl    d0,%0"                    \
  168.              : "=r"((long)NUMBER), "=d"(i)            \
  169.          : "0"((long)NUMBER), "r"((long)BASE)        \
  170.              : "d0", "d1", "a0", "a1");            \
  171.         *--BUF = digs[i];                    \
  172.     }                                \
  173.     do                                 \
  174.     {                                \
  175.             short i;                        \
  176.         __asm__ volatile("
  177.          divu    %3,%2;
  178.          swap    %0;
  179.          movw    %0,%1;
  180.          clrw    %0;
  181.                 swap    %0"                    \
  182.              : "=d"((long)NUMBER), "=g"(i)            \
  183.          : "0"((long)NUMBER), "dm"((short)BASE));    \
  184.         *--BUF = digs[i];                    \
  185.     } while(NUMBER);                        \
  186. }
  187.  
  188. #endif /* __M68020 */
  189.  
  190. #else /* !__GNUC__ */
  191.  
  192. #define _ICONV(NUMBER, BASE, BUF)                 \
  193.   do {                                \
  194.     *--(BUF) = digs[(NUMBER) % (BASE)];                \
  195.     (NUMBER) /= (BASE);                        \
  196.   } while (NUMBER);
  197.  
  198. #endif /* __GNUC__ */
  199.  
  200.  
  201. int _doprnt(fp, fmt0, argp)
  202.     register FILE *fp;
  203.     const char *fmt0;
  204.     va_list argp;
  205. {
  206.     register const u_char *fmt;    /* format string */
  207.     register int ch;    /* character from fmt */
  208.     register int cnt;    /* return value accumulator */
  209.     register int n;        /* random handy integer */
  210.     register char *t;    /* buffer pointer */
  211. #ifdef    __FLOATS__
  212. /*    double _double;        *//* double precision arguments %[eEfgG] */
  213.     union double_di _dd;    /* _double is #defined to be _dd later on */
  214.     char softsign;        /* temporary negative sign for floats */
  215. #endif    __FLOATS__
  216.     u_long _ulong;        /* integer arguments %[diouxX] */
  217.     short base;        /* base for [diouxX] conversion */
  218.     short dprec;        /* decimal precision in [diouxX] */
  219.     short fieldsz;        /* field size expanded by sign, etc */
  220.     short flags;        /* flags as above */
  221.     short fpprec;        /* `extra' floating precision in [eEfgG] */
  222.     short prec;        /* precision from format (%.3d), or -1 */
  223.     short realsz;        /* field size expanded by decimal precision */
  224.     short size;        /* size of converted field or string */
  225.     short width;        /* width from format (%8d), or 0 */
  226.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  227.     char *digs;        /* digits for [diouxX] conversion */
  228.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  229.  
  230.         t = buf;
  231.     fmt = (const u_char *) fmt0;
  232.     digs = "0123456789abcdef";
  233.     for (cnt = 0;; ++fmt) {
  234.         if ((ch = *fmt) == 0)
  235.             return (cnt);
  236.         if (ch != '%') {
  237.             PUTC(ch);
  238.             cnt++;
  239.             continue;
  240.         }
  241.         flags = 0; dprec = 0; fpprec = 0; width = 0;
  242.         prec = -1;
  243.         sign = '\0';
  244.  
  245. rflag:        switch (*++fmt) {
  246.         case ' ':
  247.             /*
  248.              * ``If the space and + flags both appear, the space
  249.              * flag will be ignored.''
  250.              *    -- ANSI X3J11
  251.              */
  252.             if (!sign)
  253.                 sign = ' ';
  254.             goto rflag;
  255.         case '#':
  256.             flags |= ALT;
  257.             goto rflag;
  258.         case '*':
  259.             /*
  260.              * ``A negative field width argument is taken as a
  261.              * - flag followed by a  positive field width.''
  262.              *    -- ANSI X3J11
  263.              * They don't exclude field widths read from args.
  264.              */
  265.             if ((width = (short)(va_arg(argp, int))) >= 0)
  266.                 goto rflag;
  267.             width = -width;
  268.             /* FALLTHROUGH */
  269.         case '-':
  270.             flags |= LADJUST;
  271.             goto rflag;
  272.         case '+':
  273.             sign = '+';
  274.             goto rflag;
  275.         case '.':
  276.             if (*++fmt == '*')
  277.                 n = va_arg(argp, int);
  278.             else {
  279.                 n = 0;
  280.                 while (isascii(*fmt) && isdigit(*fmt))
  281.                     n = TEN_MUL(n) + todigit(*fmt++);
  282.                 --fmt;
  283.             }
  284.             prec = n < 0 ? -1 : n;
  285.             goto rflag;
  286.         case '0':
  287.             /*
  288.              * ``Note that 0 is taken as a flag, not as the
  289.              * beginning of a field width.''
  290.              *    -- ANSI X3J11
  291.              */
  292.             flags |= ZEROPAD;
  293.             goto rflag;
  294.         case '1': case '2': case '3': case '4':
  295.         case '5': case '6': case '7': case '8': case '9':
  296.             n = 0;
  297.             do {
  298.                 n = TEN_MUL(n) + todigit(*fmt);
  299.             } while (isascii(*++fmt) && isdigit(*fmt));
  300.             width = n;
  301.             --fmt;
  302.             goto rflag;
  303.         case 'L':
  304.             flags |= LONGDBL;
  305.             goto rflag;
  306.         case 'h':
  307.             flags |= SHORTINT;
  308.             goto rflag;
  309.         case 'l':
  310.             flags |= LONGINT;
  311.             goto rflag;
  312.         case 'c':
  313.             *(t = buf) = va_arg(argp, int);
  314.             size = 1;
  315.             sign = '\0';
  316.             goto pforw;
  317.         case 'D':
  318.             flags |= LONGINT;
  319.             /*FALLTHROUGH*/
  320.         case 'd':
  321.         case 'i':
  322.             ARG(signed);
  323.             if ((long)_ulong < 0) {
  324.                 _ulong = -_ulong;
  325.                 sign = '-';
  326.             }
  327.             base = 10;
  328.             goto number;
  329. #ifdef __FLOATS__
  330.         case 'e':
  331.         case 'E':
  332.         case 'f':
  333.         case 'g':
  334.         case 'G':
  335.  
  336. /* mjr: check for NANs */
  337. #define    _double _dd.d
  338.             _double = va_arg(argp, double);
  339.             if (_dd.i[0] == NAN_HI)
  340.             {
  341.                 t = buf;
  342.                 t = strcpy(t, "NaN");
  343.                 size = strlen(t);
  344.                 goto pforw;
  345.             }
  346.             /*
  347.              * don't do unrealistic precision; just pad it with
  348.              * zeroes later, so buffer size stays rational.
  349.              */
  350.             if (prec > (MAXEXP - MAXFRACT)) {
  351.                 if ((*fmt != 'g' && *fmt != 'G') || (flags&ALT))
  352.                     fpprec = prec - MAXFRACT;
  353.                 prec = MAXFRACT;
  354.             }
  355.             else if (prec == -1)
  356.                 prec = DEFPREC;
  357.             /*
  358.              * softsign avoids negative 0 if _double is < 0 and
  359.              * no significant digits will be shown
  360.              */
  361.             if (_double < 0) {
  362.                 softsign = '-';
  363.                 _double = -_double;
  364.             }
  365.             else
  366.                 softsign = 0;
  367. /* hyc: check for overflows ... */
  368.             if ((((unsigned long)_dd.i[0] > INF_HI) &&
  369. /* mj: check for a negative zero; it is not smaller than zero, so it
  370.    was not negated */
  371.                  (_dd.i[0] != 0x80000000L || _dd.i[1] != 0)) ||
  372.                 ((unsigned long)_dd.i[0] == INF_HI &&
  373.                  (unsigned long)_dd.i[1] > INF_LO))
  374.               {
  375.                 t = buf;
  376.                 if(softsign == 0)
  377.                 t = strcpy(t, "NaN");
  378.                 else
  379.                 t = strcpy(t, "-NaN");
  380.                 size = strlen(t);
  381.                 goto pforw;
  382.             }
  383.             else    /* Not greater, see if equal to Inf */
  384.  
  385. /* mjr: check for +-INFINITY */
  386.             if ((unsigned long)_dd.i[0] == INF_HI)
  387.               {
  388.                 t = buf;
  389.                 if(softsign == 0)
  390.                 t = strcpy(t, "+Inf");
  391.                 else
  392.                 t = strcpy(t, "-Inf");
  393.                 size = strlen(t);
  394.                 goto pforw;
  395.             }
  396.             /*
  397.              * cvt may have to round up past the "start" of the
  398.              * buffer, i.e. ``printf("%.2f", (double)9.999);'';
  399.              * if the first char isn't '\0', it did.
  400.              */
  401.             *buf = '\0';
  402.             size = cvt(_double, (int)prec, (int)flags, &softsign,
  403.                    *fmt, buf
  404. #if !defined (__M68881__) && !defined (sfp004)
  405.                    , buf + (int)sizeof(buf)
  406. #endif
  407.                    ); 
  408.             if (softsign)
  409.                 sign = '-';
  410.             t = *buf ? buf : buf + 1;
  411.             goto pforw;
  412. #endif /* __FLOATS__ */
  413.         case 'n':
  414.             if (flags & LONGINT)
  415.                 *va_arg(argp, long *) = cnt;
  416.             else if (flags & SHORTINT)
  417.                 *va_arg(argp, short *) = cnt;
  418.             else
  419.                 *va_arg(argp, int *) = cnt;
  420.             break;
  421.         case 'O':
  422.             flags |= LONGINT;
  423.             /*FALLTHROUGH*/
  424.         case 'o':
  425.             ARG(unsigned);
  426.             base = 8;
  427.             goto nosign;
  428.         case 'p':
  429.             /*
  430.              * ``The argument shall be a pointer to void.  The
  431.              * value of the pointer is converted to a sequence
  432.              * of printable characters, in an implementation-
  433.              * defined manner.''
  434.              *    -- ANSI X3J11
  435.              */
  436.             /* NOSTRICT */
  437.             _ulong = (u_long)va_arg(argp, void *);
  438.             base = 16;
  439.             goto nosign;
  440.         case 's':
  441.             if ((t = va_arg(argp, char *)) == 0)
  442.                 t = "(null)";
  443.             if (prec >= 0) {
  444.                 /*
  445.                  * can't use strlen; can only look for the
  446.                  * NUL in the first `prec' characters, and
  447.                  * strlen() will go further.
  448.                  */
  449. #ifdef __STDC__
  450.                 char *p;
  451.                 void *memchr(const void *, int, size_t);
  452. #else
  453.                 char *p, *memchr();
  454. #endif
  455.  
  456.                 if ((p = (char *)memchr(t, 0, (size_t)prec)) != NULL) {
  457.                     size = p - t;
  458.                     if (size > prec)
  459.                         size = prec;
  460.                 } else
  461.                     size = prec;
  462.             } else
  463.                 size = (int)strlen(t);
  464.             sign = '\0';
  465.             goto pforw;
  466.         case 'U':
  467.             flags |= LONGINT;
  468.             /*FALLTHROUGH*/
  469.         case 'u':
  470.             ARG(unsigned);
  471.             base = 10;
  472.             goto nosign;
  473.         case 'X':
  474.             digs = "0123456789ABCDEF";
  475.             /* FALLTHROUGH */
  476.         case 'x':
  477.             ARG(unsigned);
  478.             base = 16;
  479.             /* leading 0x/X only if non-zero */
  480.             if (flags & ALT && _ulong != 0)
  481.                 flags |= HEXPREFIX;
  482.  
  483.             /* unsigned conversions */
  484. nosign:            sign = '\0';
  485.             /*
  486.              * ``... diouXx conversions ... if a precision is
  487.              * specified, the 0 flag will be ignored.''
  488.              *    -- ANSI X3J11
  489.              */
  490. number:            if ((dprec = prec) >= 0)
  491.                 flags &= ~ZEROPAD;
  492.  
  493.             /*
  494.              * ``The result of converting a zero value with an
  495.              * explicit precision of zero is no characters.''
  496.              *    -- ANSI X3J11
  497.              */
  498.             t = buf + BUF;
  499.             if (_ulong != 0 || prec != 0) {
  500.                 _ICONV(_ulong, base, t);
  501.                 digs = "0123456789abcdef";
  502.                 if (flags & ALT && base == 8 && *t != '0')
  503.                     *--t = '0'; /* octal leading 0 */
  504.             }
  505.             size = buf + BUF - t;
  506.  
  507. pforw:
  508.             /*
  509.              * All reasonable formats wind up here.  At this point,
  510.              * `t' points to a string which (if not flags&LADJUST)
  511.              * should be padded out to `width' places.  If
  512.              * flags&ZEROPAD, it should first be prefixed by any
  513.              * sign or other prefix; otherwise, it should be blank
  514.              * padded before the prefix is emitted.  After any
  515.              * left-hand padding and prefixing, emit zeroes
  516.              * required by a decimal [diouxX] precision, then print
  517.              * the string proper, then emit zeroes required by any
  518.              * leftover floating precision; finally, if LADJUST,
  519.              * pad with blanks.
  520.              */
  521.  
  522.             /*
  523.              * compute actual size, so we know how much to pad
  524.              * fieldsz excludes decimal prec; realsz includes it
  525.              */
  526.             fieldsz = size + fpprec;
  527.             if (sign)
  528.                 fieldsz++;
  529.             if (flags & HEXPREFIX)
  530.                 fieldsz += 2;
  531.             realsz = dprec > fieldsz ? dprec : fieldsz;
  532.  
  533.             /* right-adjusting blank padding */
  534.             if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
  535.                 for (n = realsz; n < width; n++)
  536.                     PUTC(' ');
  537.             /* prefix */
  538.             if (sign)
  539.                 PUTC(sign);
  540.             if (flags & HEXPREFIX) {
  541.                 PUTC('0');
  542.                 PUTC((char)*fmt);
  543.             }
  544.             /* right-adjusting zero padding */
  545.             if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  546.                 for (n = realsz; n < width; n++)
  547.                     PUTC('0');
  548.             /* leading zeroes from decimal precision */
  549.             for (n = fieldsz; n < dprec; n++)
  550.                 PUTC('0');
  551.  
  552. #ifdef __FLOATS__
  553.             if (fpprec > 0)
  554.               {
  555.                 /* the number without exponent */
  556.                 n = size;
  557.                 while (*t != 'e' && *t != 'E' && --n >= 0)
  558.                   PUTC (*t++);
  559.               }
  560.             else
  561. #endif
  562.             /* the string or number proper */
  563.             for (n = size; --n >= 0; )
  564.                 PUTC(*t++);
  565.             /* trailing f.p. zeroes */
  566.             while (--fpprec >= 0)
  567.                 PUTC('0');
  568. #ifdef __FLOATS__
  569.             /* exponent */
  570.             while (--n >= 0)
  571.               PUTC (*t++);
  572. #endif
  573.             /* left-adjusting padding (always blank) */
  574.             if (flags & LADJUST)
  575.                 for (n = realsz; n < width; n++)
  576.                     PUTC(' ');
  577.             /* finally, adjust cnt */
  578.             cnt += width > realsz ? width : realsz;
  579.             break;
  580.         case '\0':    /* "%?" prints ?, unless ? is NULL */
  581.             return (cnt);
  582.         default:
  583.             PUTC((char)*fmt);
  584.             cnt++;
  585.         }
  586.     }
  587.     /* NOTREACHED */
  588. }
  589.  
  590. #ifdef __FLOATS__
  591. #if defined (__M68881__) || defined (sfp004)
  592.  
  593. /* Format of packed decimal (from left to right):
  594.  
  595.     1 Bit: sign of mantissa
  596.     1 Bit: sign of exponent
  597.     2 Bits zero
  598.    12 Bits: three digits exponent
  599.     4 Bits unused, fourth (higher order) digit of exponent
  600.     8 Bits zero
  601.    68 Bits: 17 digits of mantissa, decimal point after first digit
  602.   --------
  603.    96 Bits == 12 Bytes
  604.  
  605.    All numbers in BCD format.  */
  606.  
  607. #ifdef sfp004
  608. /* Note: not tested -- schwab */
  609.  
  610. /* static */ void Format __PROTO ((double number, char *buf));
  611.  
  612. asm (
  613. "comm = -6;\n"
  614. "resp = -16;\n"
  615. ".text\n"
  616. ".even\n"
  617. "_Format:\n"
  618. "    lea    0xfffffa50:w,a0            | fpu address\n"
  619. "    lea    sp@(4),a1            | argptr\n"
  620.  
  621. "    movew    #0x5400,a0@(comm)        | fmoved -> fp0\n"
  622. "1:    cmpw    #0x8900,a0@(resp)\n"
  623. "    beq    1b\n"
  624. "    movel    a1@+,a0@\n"
  625. "    movel    a1@+,a0@\n"
  626.  
  627. "    movel    a1@,a1                | get buf\n"
  628. "    movew    #0x6c11,a0@(comm)        | fmovep fp0,a1@{#17}\n"
  629. "1:    cmpw    #0x8900,a0@(resp)\n"
  630. "    beq    1b\n"
  631. "    movel    a0@,a1@+\n"
  632. "    movel    a0@,a1@+\n"
  633. "    movel    a0@,a1@+\n"
  634. "    rts\n"
  635. );
  636. #endif /* sfp004 */
  637.     
  638. static int
  639. cvt (number, prec, flags, signp, fmtch, startp)
  640.      double number;
  641.      int prec, flags, fmtch;
  642.      char *signp, *startp;
  643. {
  644.   char buf[12];
  645.   char digits[18];
  646.   int i;
  647.   char *p, *t;
  648.   int expcnt;
  649.   int gformat = 0, dotrim;
  650.  
  651.   /* Convert to packed decimal.  */
  652. #ifdef sfp004
  653.   Format (number, buf);
  654. #else
  655.   asm volatile ("fmovep %0,%1{#17}" : : "f" (number), "m" (buf[0]));
  656. #endif
  657.   /* Unpack it. */
  658.   p = buf + 3;
  659.   for (i = 0; i < 17; i++)
  660.     digits[i] = ((i & 1 ? *p >> 4 : *p++) & 15) + '0';
  661.   digits[i] = 0;
  662.   expcnt = ((buf[0] & 15) * 10 + ((buf[1] >> 4) & 15)) * 10 + (buf[1] & 15);
  663.   if (buf[0] & 0x40)
  664.     expcnt = -expcnt;
  665.   t = ++startp;
  666.   p = digits;
  667.   switch (fmtch)
  668.     {
  669.     case 'f':
  670.       if (expcnt >= 0)
  671.     {
  672.       *t++ = *p++;
  673.       while (expcnt > 0 && *p)
  674.         {
  675.           *t++ = *p++;
  676.           expcnt--;
  677.         }
  678.       while (expcnt > 0)
  679.         {
  680.           *t++ = '0';
  681.           expcnt--;
  682.         }
  683.     }
  684.       else
  685.     {
  686.       /* Note: decimal point after the first digit. */
  687.       expcnt++;
  688.       *t++ = '0';
  689.     }
  690.       if (prec || flags & ALT)
  691.     *t++ = '.';
  692.       while (prec > 0 && expcnt < 0)
  693.     {
  694.       *t++ = '0';
  695.       prec--;
  696.       expcnt++;
  697.     }
  698.       while (prec > 0 && *p)
  699.     {
  700.       *t++ = *p++;
  701.       prec--;
  702.     }
  703.       if (*p)
  704.     if (_round (*p, startp, t - 1, signp))
  705.       *--startp = '1';
  706.       while (prec > 0)
  707.     {
  708.       *t++ = '0';
  709.       prec--;
  710.     }
  711.       break;
  712.  
  713.     case 'e':
  714.     case 'E':
  715.     eformat:
  716.       *t++ = *p++;
  717.       if (prec || flags & ALT)
  718.     *t++ = '.';
  719.       while (prec > 0 && *p)
  720.     {
  721.       *t++ = *p++;
  722.       prec--;
  723.     }
  724.       if (*p)
  725.     if (_round (*p, startp, t - 1, signp))
  726.       {
  727.         expcnt++;
  728.         *startp = '1';
  729.       }
  730.       if (!gformat || flags & ALT)
  731.     {
  732.       while (prec > 0)
  733.         {
  734.           *t++ = '0';
  735.           prec--;
  736.         }
  737.     }
  738.       else
  739.     {
  740.       /* Suppress trailing zero's. */
  741.       while (t > startp && t[-1] == '0')
  742.         t--;
  743.       if (t[-1] == '.')
  744.         t--;
  745.     }
  746.       t = exponent (t, expcnt, fmtch);
  747.       break;
  748.  
  749.     case 'g':
  750.     case 'G':
  751.       if (prec == 0)
  752.     prec++;
  753.       /* If the exponent is not less than the precision or less than -4,
  754.      use 'e' format, otherwise use 'f' format.  */
  755.       if (expcnt >= prec || expcnt < -4)
  756.     {
  757.       /* Count the significant digit before the decimal point.  */
  758.       prec--;
  759.       /* 'g'/'G' -> 'e'/'E' */
  760.       fmtch -= 2;
  761.       gformat = 1;
  762.       goto eformat;
  763.     }
  764.       /* Like 'f', but prec counts significant digits.  */
  765.       if (expcnt >= 0)
  766.     {
  767.       *t++ = *p++;
  768.       prec--;
  769.       /* Note that prec >= expcnt */
  770.       while (expcnt > 0 && *p)
  771.         {
  772.           *t++ = *p++;
  773.           expcnt--;
  774.           prec--;
  775.         }
  776.       while (expcnt > 0)
  777.         {
  778.           *t++ = '0';
  779.           expcnt--;
  780.           prec--;
  781.         }
  782.     }
  783.       else
  784.     {
  785.       *t++ = '0';
  786.       expcnt++;
  787.     }
  788.       if (prec > 0 || flags & ALT)
  789.     {
  790.       dotrim = 1;
  791.       *t++ = '.';
  792.     }
  793.       else
  794.     dotrim = 0;
  795.       if (prec > 0)
  796.     /* Pad with 0's */
  797.     while (expcnt < 0)
  798.       {
  799.         *t++ = '0';
  800.         expcnt++;
  801.       }
  802.       /* While more precision required and digits left */
  803.       while (prec > 0 && *p)
  804.     {
  805.       *t++ = *p++;
  806.       prec--;
  807.     }
  808.       if (*p)
  809.     if (_round (*p, startp, t - 1, signp))
  810.       /* Overflow, e.g. 9.999 -> 10.000 */
  811.       *--startp = '1';
  812.       if (flags & ALT)
  813.     {
  814.       while (prec > 0)
  815.         {
  816.           *t++ = '0';
  817.           prec--;
  818.         }
  819.     }
  820.       else if (dotrim)
  821.     {
  822.       /* Strip trailing 0's. */
  823.       while (t > startp && *--t == '0');
  824.       if (*t != '.')
  825.         t++;
  826.     }
  827.       break;
  828.     }
  829.   return (int) (t - startp);
  830. }
  831.  
  832. static int
  833. _round (nxtdig, start, end, signp)
  834.      int nxtdig;
  835.      char *start, *end;
  836.      char *signp;
  837. {
  838.   if (nxtdig > '4')
  839.     {
  840.       for (;; --end)
  841.     {
  842.       if (*end == '.')
  843.         --end;
  844.       if (++*end <= '9')
  845.         break;
  846.       *end = '0';
  847.       if (end == start)
  848.         /* Report overflow, caller must handle appropriately.  */
  849.         return 1;
  850.     }
  851.     }
  852.   else if (*signp == '-')
  853.     {
  854.       for (;; --end)
  855.     {
  856.       if (*end == '.')
  857.         --end;
  858.       if (*end != '0')
  859.         break;
  860.       if (end == start)
  861.         *signp = 0;
  862.     }
  863.     }
  864.   return 0;
  865. }
  866.  
  867. #else /* !(__M68881__ || sfp004) */
  868.  
  869. static int
  870. cvt(number,prec,flags, signp, fmtch, startp, endp)
  871.     double number;
  872.     register int prec;
  873.     int flags;
  874.     int fmtch;
  875.     char *signp, *startp, *endp;
  876. {
  877.     register char *p, *t;
  878.     register double fract;
  879.     int dotrim, expcnt, gformat;
  880.     double integer, tmp, modf __PROTO((double, double *));
  881.     char *exponent __PROTO((char *, int, int)),
  882.          *_round __PROTO((double, int *, char *, char *, int, char *));
  883.  
  884.     dotrim = expcnt = gformat = 0;
  885.     fract = modf(number, &integer);
  886.  
  887.     /* get an extra slot for rounding. */
  888.     t = ++startp;
  889. /* jrb -- #define DBL_EPSILON 1.1107651257113995e-16 */ /* mjr ++ */
  890.     /*
  891.      * get integer portion of number; put into the end of the buffer; the
  892.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  893.      */
  894.     for (p = endp - 1; integer; ++expcnt) {
  895.         tmp = modf(integer / 10, &integer);
  896.         *p-- = tochar((int)((tmp + .01) * 10));
  897. /* await michals advise on this    -- in the mean while use above line
  898.     *p-- = tochar((int)((tmp + DBL_EPSILON) * 10));
  899.  */
  900.     }
  901.     switch(fmtch) {
  902.     case 'f':
  903.         /* reverse integer into beginning of buffer */
  904.         if (expcnt)
  905.             for (; ++p < endp; *t++ = *p);
  906.         else
  907.             *t++ = '0';
  908.         /*
  909.          * if precision required or alternate flag set, add in a
  910.          * decimal point.
  911.          */
  912.         if (prec || flags&ALT)
  913.             *t++ = '.';
  914.         /* if requires more precision and some fraction left */
  915.         if (fract) {
  916.             if (prec)
  917.                 do {
  918.                     fract = modf(fract * 10, &tmp);
  919.                     *t++ = tochar((int)tmp);
  920.                 } while (--prec && fract);
  921.             if (fract)
  922.                 startp = _round(fract, (int *)NULL, startp,
  923.                     t - 1, (char)0, signp);
  924.         }
  925.         for (; prec--; *t++ = '0');
  926.         break;
  927.     case 'e':
  928.     case 'E':
  929. eformat:    if (expcnt) {
  930.             *t++ = *++p;
  931.             if (prec || flags&ALT)
  932.                 *t++ = '.';
  933.             /* if requires more precision and some integer left */
  934.             for (; prec && ++p < endp; --prec)
  935.                 *t++ = *p;
  936.             /*
  937.              * if done precision and more of the integer component,
  938.              * round using it; adjust fract so we don't re-round
  939.              * later.
  940.              */
  941.             if (!prec && ++p < endp) {
  942.                 fract = 0;
  943.                 startp = _round((double)0, &expcnt, startp,
  944.                     t - 1, *p, signp);
  945.             }
  946.             /* adjust expcnt for digit in front of decimal */
  947.             --expcnt;
  948.         }
  949.         /* until first fractional digit, decrement exponent */
  950.         else if (fract) {
  951.             /* adjust expcnt for digit in front of decimal */
  952.             for (expcnt = -1;; --expcnt) {
  953.                 fract = modf(fract * 10, &tmp);
  954.                 if (tmp)
  955.                     break;
  956.             }
  957.             *t++ = tochar((int)tmp);
  958.             if (prec || flags&ALT)
  959.                 *t++ = '.';
  960.         }
  961.         else {
  962.             *t++ = '0';
  963.             if (prec || flags&ALT)
  964.                 *t++ = '.';
  965.         }
  966.         /* if requires more precision and some fraction left */
  967.         if (fract) {
  968.             if (prec)
  969.                 do {
  970.                     fract = modf(fract * 10, &tmp);
  971.                     *t++ = tochar((int)tmp);
  972.                 } while (--prec && fract);
  973.             if (fract)
  974.                 startp = _round(fract, &expcnt, startp,
  975.                     t - 1, (char)0, signp);
  976.         }
  977.         /* if requires more precision */
  978.         for (; prec--; *t++ = '0');
  979.  
  980.         /* unless alternate flag, trim any g/G format trailing 0's */
  981.         if (gformat && !(flags&ALT)) {
  982.             while (t > startp && *--t == '0');
  983.             if (*t == '.')
  984.                 --t;
  985.             ++t;
  986.         }
  987.         t = exponent(t, expcnt, fmtch);
  988.         break;
  989.     case 'g':
  990.     case 'G':
  991.         /* a precision of 0 is treated as a precision of 1. */
  992.         if (!prec)
  993.             ++prec;
  994.         /*
  995.          * ``The style used depends on the value converted; style e
  996.          * will be used only if the exponent resulting from the
  997.          * conversion is less than -4 or greater than the precision.''
  998.          *    -- ANSI X3J11
  999.          */
  1000.         if (expcnt > prec || (!expcnt && fract && fract < .0001)) {
  1001.             /*
  1002.              * g/G format counts "significant digits, not digits of
  1003.              * precision; for the e/E format, this just causes an
  1004.              * off-by-one problem, i.e. g/G considers the digit
  1005.              * before the decimal point significant and e/E doesn't
  1006.              * count it as precision.
  1007.              */
  1008.             --prec;
  1009.             fmtch -= 2;        /* G->E, g->e */
  1010.             gformat = 1;
  1011.             goto eformat;
  1012.         }
  1013.         /*
  1014.          * reverse integer into beginning of buffer,
  1015.          * note, decrement precision
  1016.          */
  1017.         if (expcnt)
  1018.             for (; ++p < endp; *t++ = *p, --prec);
  1019.         else
  1020.             *t++ = '0';
  1021.         /*
  1022.          * if precision required or alternate flag set, add in a
  1023.          * decimal point.  If no digits yet, add in leading 0.
  1024.          */
  1025.         if (prec || flags&ALT) {
  1026.             dotrim = 1;
  1027.             *t++ = '.';
  1028.         }
  1029.         else
  1030.             dotrim = 0;
  1031.         /* if requires more precision and some fraction left */
  1032.         if (fract) {
  1033.             if (prec) {
  1034.                 if (0 == expcnt) {
  1035.                     /* if no significant digits yet */
  1036.                     do {
  1037.                         fract = modf(fract * 10, &tmp);
  1038.                         *t++ = tochar((int)tmp);
  1039.                     } while(!tmp);
  1040.                     prec--;
  1041.                 }
  1042.                 while (prec && fract) {
  1043.                     fract = modf(fract * 10, &tmp);
  1044.                     *t++ = tochar((int)tmp);
  1045.                     prec--;
  1046.                 }
  1047.             }
  1048.             if (fract)
  1049.                 startp = _round(fract, (int *)NULL, startp,
  1050.                     t - 1, (char)0, signp);
  1051.         }
  1052.         /* alternate format, adds 0's for precision, else trim 0's */
  1053.         if (flags&ALT)
  1054.             for (; prec--; *t++ = '0');
  1055.         else if (dotrim) {
  1056.             while (t > startp && *--t == '0');
  1057.             if (*t != '.')
  1058.                 ++t;
  1059.         }
  1060.     }
  1061.     return((int)(t - startp));
  1062. }
  1063.  
  1064. static char *
  1065. _round(fract, exp, start, end, ch, signp)
  1066.     double fract;
  1067.     int *exp;
  1068.     register char *start, *end;
  1069.     int ch;
  1070.     char *signp;
  1071. {
  1072.     double tmp;
  1073.  
  1074.     if (fract)
  1075.         (void)modf(fract * 10, &tmp);
  1076.     else
  1077.         tmp = todigit(ch);
  1078.     if (tmp > 4)
  1079.         for (;; --end) {
  1080.             if (*end == '.')
  1081.                 --end;
  1082.             if (++*end <= '9')
  1083.                 break;
  1084.             *end = '0';
  1085.             if (end == start) {
  1086.                 if (exp) {    /* e/E; increment exponent */
  1087.                     *end = '1';
  1088.                     ++*exp;
  1089.                 }
  1090.                 else {        /* f; add extra digit */
  1091.                     *--end = '1';
  1092.                     --start;
  1093.                 }
  1094.                 break;
  1095.             }
  1096.         }
  1097.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  1098.     else if (*signp == '-')
  1099.         for (;; --end) {
  1100.             if (*end == '.')
  1101.                 --end;
  1102.             if (*end != '0')
  1103.                 break;
  1104.             if (end == start)
  1105.                 *signp = 0;
  1106.         }
  1107.     return(start);
  1108. }
  1109.  
  1110. #endif /* !(__M68881__ || sfp004) */
  1111.  
  1112. static char *
  1113. exponent(p, exp, fmtch)
  1114.     register char *p;
  1115.     register int exp;
  1116.     int fmtch;
  1117. {
  1118.     register char *t;
  1119.     char expbuf[MAXEXP];
  1120.  
  1121.     *p++ = fmtch;
  1122.     if (exp < 0) {
  1123.         exp = -exp;
  1124.         *p++ = '-';
  1125.     }
  1126.     else
  1127.         *p++ = '+';
  1128.     t = expbuf + MAXEXP;
  1129.     if (exp > 9) {
  1130.         do {
  1131.             *--t = tochar(exp % 10);
  1132.         } while ((exp /= 10) > 9);
  1133.         *--t = tochar(exp);
  1134.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  1135.     }
  1136.     else {
  1137.         *p++ = '0';
  1138.         *p++ = tochar(exp);
  1139.     }
  1140.     return(p);
  1141. }
  1142. #endif /* __FLOATS__ */
  1143.