home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / g__~1 / gplibs17.zoo / outfloat.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-02  |  5.6 KB  |  187 lines

  1. //    This is part of the iostream library, providing input/output for C++.
  2. //    Copyright (C) 1992 Per Bothner.
  3. //
  4. //    This library is free software; you can redistribute it and/or
  5. //    modify it under the terms of the GNU Library General Public
  6. //    License as published by the Free Software Foundation; either
  7. //    version 2 of the License, or (at your option) any later version.
  8. //
  9. //    This library is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. //    Library General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU Library General Public
  15. //    License along with this library; if not, write to the Free
  16. //    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include <ioprivat.h>
  19.  
  20. // Format floating-point number and print them.
  21. // Return number of chars printed, or EOF on error.
  22.  
  23. // sign_mode == '+' : print "-" or "+"
  24. // sign_mode == ' ' : print "-" or " "
  25. // sign_mode == '\0' : print "-' or ""
  26.  
  27. int __outfloat(double value, streambuf *sb, char type,
  28.            int width, int precision, ios::fmtflags flags,
  29.            char sign_mode, char fill)
  30. {
  31.     int count = 0;
  32. #define PUT(x) do {if (sb->sputc(x) < 0) goto error; count++;} while (0)
  33. #define PUTN(p, n) \
  34.   do {_G_size_t _n=n; count+=_n; if (sb->sputn(p,_n) != _n) goto error;} while(0)
  35. #define PADN(fill, n) \
  36.   do {_G_size_t _n = n; count+=_n; if (sb->padn(fill, _n) < 0) goto error;} while (0)
  37.     ios::fmtflags pad_kind = flags & (ios::left|ios::right|ios::internal);
  38.     int skip_zeroes = 0;
  39.     int show_dot = (flags & ios::showpoint) != 0;
  40.     int decpt;
  41.     int sign;
  42.     int mode;
  43. #define EBUF_SIZE 12
  44. #define EBUF_END &ebuf[EBUF_SIZE]
  45.     char ebuf[EBUF_SIZE];
  46.     char *end;
  47.     int exp = 0;
  48.     switch (type) {
  49.       case 'f':
  50.     mode = 3;
  51.     break;
  52.       case 'F':
  53.     exp = 'e';
  54.     mode = 0;
  55.     skip_zeroes = 1;
  56.     type = 'g';
  57.     break;
  58.       case 'e':
  59.     exp = 'e';
  60.     mode = 2;
  61.     precision++;  // Add one to include digit before decimal point.
  62.     break;
  63.       case 'E':
  64.     exp = 'E';
  65.     mode = 2;
  66.     precision++;  // Add one to include digit before decimal point.
  67.     break;
  68.       case 'g':
  69.       case 'G':
  70.     exp = type == 'g' ? 'e' : 'E';
  71.     if (precision == 0) precision = 1;
  72.     if (!(flags & ios::showpoint))
  73.         skip_zeroes = 1;
  74.     type = 'g';
  75.     mode = 2;
  76.     break;
  77.     }
  78.     /* Do the actual convension */
  79.     char *p = dtoa(value, mode, precision, &decpt, &sign, &end);
  80.     register int i;
  81.     int useful_digits = end-p;
  82.     char *exponent_start = EBUF_END;
  83.     // Check if we need to emit an exponent.
  84.     if (mode != 3 && decpt != 9999) {
  85.     i = decpt - 1;
  86.     if ((type != 'g' && type != 'F') || i < -4 || i >= precision) {
  87.         // Print the exponent into ebuf.
  88.         // We write ebuf in reverse order (right-to-left).
  89.         char sign;
  90.         if (i >= 0)
  91.         sign = '+';
  92.         else
  93.         sign = '-', i = -i;
  94.         /* Note: ANSI requires at least 2 exponent digits. */
  95.         do {
  96.         *--exponent_start = (i % 10) + '0';
  97.         i /= 10;
  98.         } while (i >= 10);
  99.         *--exponent_start = i + '0';
  100.         *--exponent_start = sign;
  101.         *--exponent_start = exp;
  102.     }
  103.     }
  104.     int exponent_size = EBUF_END - exponent_start;
  105.     if (mode == 1)
  106.     precision = 1;
  107.     /* If we print an exponent, always show just one digit before point. */
  108.     if (exponent_size)
  109.     decpt = 1;
  110.     if (decpt == 9999) { // Infinity or NaN
  111.     decpt = useful_digits;
  112.     precision = 0;
  113.     show_dot = 0;
  114.     }
  115.  
  116.    // dtoa truncates trailing zeroes.  Set the variable trailing_zeroes to
  117.    // the number of 0's we have to add (after the decimal point).
  118.    int trailing_zeroes = 0;
  119.    if (skip_zeroes)
  120.        trailing_zeroes = 0;
  121.    else if (type == 'f')
  122.        trailing_zeroes = useful_digits <= decpt ? precision
  123.        : precision-(useful_digits-decpt);
  124.    else if (exponent_size) // 'e' 'E' or 'g' format using exponential notation.
  125.        trailing_zeroes = precision - useful_digits;
  126.    else // 'g' format not using exponential notation.
  127.        trailing_zeroes = useful_digits <= decpt ? precision - decpt
  128.        : precision-useful_digits;
  129.     if (trailing_zeroes < 0) trailing_zeroes = 0;
  130.  
  131.     if (trailing_zeroes != 0 || useful_digits > decpt)
  132.     show_dot = 1;
  133.     int print_sign;
  134.     if (sign_mode == 0)
  135.     print_sign = sign ? '-' : 0;
  136.     else if (sign_mode == '+')
  137.     print_sign = sign ? '-' : '+';
  138.     else /* if (sign_mode == ' ') */
  139.     print_sign = sign ? '-' : ' ';
  140.     
  141.     // Calculate the width (before padding).
  142.     int unpadded_width =
  143.     (print_sign != 0) + trailing_zeroes + exponent_size + show_dot
  144.         + useful_digits + (decpt > 0 ? 0 : 1 - decpt);
  145.  
  146.     int padding = width > unpadded_width ? width - unpadded_width : 0;
  147.     if (padding > 0
  148.     && pad_kind != (ios::fmtflags)ios::left
  149.     && pad_kind != (ios::fmtflags)ios::internal) // Default (right) adjust.
  150.     PADN(fill, padding);
  151.     if (print_sign)
  152.     PUT(print_sign);
  153.     if (pad_kind == (ios::fmtflags)ios::internal && padding > 0)
  154.     PADN(fill, padding);
  155.     if (decpt > 0) {
  156.     if (useful_digits >= decpt)
  157.         PUTN(p, decpt);
  158.     else {
  159.         PUTN(p, useful_digits);
  160.         PADN('0', decpt-useful_digits);
  161.     }
  162.     if (show_dot) {
  163.         PUT('.');
  164.         // Print digits after the decimal point.
  165.         if (useful_digits > decpt)
  166.         PUTN(p + decpt, useful_digits-decpt);
  167.     }
  168.     }
  169.     else {
  170.     PUT('0');
  171.     if (show_dot) {
  172.         PUT('.');
  173.         PADN('0', -decpt);
  174.         // Print digits after the decimal point.
  175.         PUTN(p, useful_digits);
  176.     }
  177.     }
  178.     PADN('0', trailing_zeroes);
  179.     if (exponent_size)
  180.     PUTN(exponent_start, exponent_size);
  181.     if (pad_kind == (ios::fmtflags)ios::left && padding > 0) // Left adjustment
  182.     PADN(fill, padding);
  183.     return count;
  184.   error:
  185.     return EOF;
  186. }
  187.