home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / g__~1 / gplibs15.zoo / outfloat.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-23  |  4.7 KB  |  164 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. // sign_mode == '+' : print "-" or "+"
  21. // sign_mode == ' ' : print "-" or " "
  22. // sign_mode == '\0' : print "-' or ""
  23.  
  24. int __outfloat(double value, streambuf *sb, char type,
  25.            int width, int precision, ios::fmtflags flags,
  26.            char sign_mode, char fill)
  27. {
  28. #define PUT(x) do {if (sb->sputc(x) < 0) goto error;} while (0)
  29. #define PUTN(p, n) \
  30.    do {int __n=n;if (sb->sputn(p, __n) != __n) goto error;} while (0)
  31. #define PADN(fill, n) do {if (sb->padn(fill, n) < 0) goto error;} while (0)
  32.     ios::fmtflags pad_kind = flags & (ios::left|ios::right|ios::internal);
  33.     int skip_zeroes = 0;
  34.     int show_dot = flags & ios::showpoint;
  35.     int decpt;
  36.     int sign;
  37.     int mode;
  38. #define EBUF_SIZE 12
  39. #define EBUF_END &ebuf[EBUF_SIZE]
  40.     char ebuf[EBUF_SIZE];
  41.     char *end;
  42.     int exp = 0;
  43.     switch (type) {
  44.       case 'f':
  45.     mode = 3;
  46.     break;
  47.       case 'F':
  48.     exp = 'e';
  49.     mode = 0;
  50.     type = 'g';
  51.     break;
  52.       case 'e':
  53.     exp = 'e';
  54.     mode = 2;
  55.     break;
  56.       case 'E':
  57.     exp = 'E';
  58.     mode = 2;
  59.     break;
  60.       case 'g':
  61.       case 'G':
  62.     exp = type == 'g' ? 'e' : 'E';
  63.     if (precision == 0) precision = 1;
  64.     if (!(flags & ios::showpoint))
  65.         skip_zeroes = 1;
  66.     type = 'g';
  67.     mode = 2;
  68.     break;
  69.     }
  70.     /* Do the actual convension */
  71.     char *p = dtoa(value, mode, precision, &decpt, &sign, &end);
  72.     register int i;
  73.     int useful_digits = end-p;
  74.     char *exponent_start = EBUF_END;
  75.     // Check if we need to emit an exponent.
  76.     if (mode != 3 && decpt != 9999) {
  77.     i = decpt - 1;
  78.     if ((type != 'g' && type != 'F') || i <= -4 || i >= precision) {
  79.         // Print the exponent into ebuf.
  80.         // We write ebuf in reverse order (right-to-left).
  81.         char sign;
  82.         if (i >= 0)
  83.         sign = '+';
  84.         else
  85.         sign = '-', i = -i;
  86.         /* Note: ANSI requires at least 2 exponent digits. */
  87.         do {
  88.         *--exponent_start = (i % 10) + '0';
  89.         i /= 10;
  90.         } while (i >= 10);
  91.         *--exponent_start = i + '0';
  92.         *--exponent_start = sign;
  93.         *--exponent_start = exp;
  94.     }
  95.     }
  96.     int exponent_size = EBUF_END - exponent_start;
  97.     if (mode == 1)
  98.     precision = 1;
  99.     /* If we print an exponent, always show just one digit before point. */
  100.     if (exponent_size)
  101.     decpt = 1;
  102.     if (decpt == 9999) { // Infinity or NaN
  103.     decpt = useful_digits;
  104.     precision = 0;
  105.     show_dot = 0;
  106.     }
  107.     int trailing_zeroes = skip_zeroes ? 0 : precision-(useful_digits-decpt);
  108.     if (trailing_zeroes < 0) trailing_zeroes = 0;
  109.     if (trailing_zeroes != 0 || useful_digits > decpt)
  110.     show_dot = 1;
  111.     int print_dot = 1;
  112.     int print_sign;
  113.     if (sign_mode == 0)
  114.     print_sign = sign ? '-' : 0;
  115.     else if (sign_mode == '+')
  116.     print_sign = sign ? '-' : '+';
  117.     else /* if (sign_mode == ' ') */
  118.     print_sign = sign ? '-' : ' ';
  119.     
  120.     // Calculate the width (before padding).
  121.     int unpadded_width =
  122.     (print_sign != 0) + trailing_zeroes + exponent_size + show_dot
  123.         + useful_digits + (decpt > 0 ? 0 : 1 - decpt);
  124.  
  125.     int padding = width > unpadded_width ? width - unpadded_width : 0;
  126.     if (padding > 0
  127.     && pad_kind != (ios::fmtflags)ios::left
  128.     && pad_kind != (ios::fmtflags)ios::internal) // Default (right) adjust.
  129.     PADN(fill, padding);
  130.     if (print_sign)
  131.     PUT(print_sign);
  132.     if (pad_kind == (ios::fmtflags)ios::internal && padding > 0)
  133.     PADN(fill, padding);
  134.     if (decpt > 0) {
  135.     if (useful_digits >= decpt)
  136.         PUTN(p, decpt);
  137.     else {
  138.         PUTN(p, useful_digits);
  139.         PADN('0', decpt-useful_digits);
  140.     }
  141.     if (show_dot) {
  142.         PUT('.');
  143.         // Print digits after the decimal point.
  144.         if (useful_digits > decpt)
  145.         PUTN(p + decpt, useful_digits-decpt);
  146.     }
  147.     }
  148.     else {
  149.     PUT('0');
  150.     PUT('.');
  151.     PADN('0', -decpt);
  152.     // Print digits after the decimal point.
  153.     PUTN(p, useful_digits);
  154.     }
  155.     PADN('0', trailing_zeroes);
  156.     if (exponent_size)
  157.     PUTN(exponent_start, exponent_size);
  158.     if (pad_kind == (ios::fmtflags)ios::left && padding > 0) // Left adjustment
  159.     PADN(fill, padding);
  160.     return 0;
  161.   error:
  162.     return EOF;
  163. }
  164.