home *** CD-ROM | disk | FTP | other *** search
- // This is part of the iostream library, providing input/output for C++.
- // Copyright (C) 1992 Per Bothner.
- //
- // This library is free software; you can redistribute it and/or
- // modify it under the terms of the GNU Library General Public
- // License as published by the Free Software Foundation; either
- // version 2 of the License, or (at your option) any later version.
- //
- // This library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- // Library General Public License for more details.
- //
- // You should have received a copy of the GNU Library General Public
- // License along with this library; if not, write to the Free
- // Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- #include "ioprivate.h"
- #ifdef USE_DTOA
-
- // Format floating-point number and print them.
- // Return number of chars printed, or EOF on error.
-
- // sign_mode == '+' : print "-" or "+"
- // sign_mode == ' ' : print "-" or " "
- // sign_mode == '\0' : print "-' or ""
-
- int __outfloat(double value, streambuf *sb, char type,
- int width, int precision, ios::fmtflags flags,
- char sign_mode, char fill)
- {
- int count = 0;
- #define PUT(x) do {if (sb->sputc(x) < 0) goto error; count++;} while (0)
- #define PUTN(p, n) \
- do {int _n=n; count+=_n; if (sb->sputn(p,_n) != _n) goto error;} while(0)
- #define PADN(fill, n) \
- do {int _n = n; count+=_n; if (sb->padn(fill, _n) < 0) goto error;} while (0)
- ios::fmtflags pad_kind = flags & (ios::left|ios::right|ios::internal);
- int skip_zeroes = 0;
- int show_dot = (flags & ios::showpoint) != 0;
- int decpt;
- int sign;
- int mode;
- #define EBUF_SIZE 12
- #define EBUF_END &ebuf[EBUF_SIZE]
- char ebuf[EBUF_SIZE];
- char *end;
- int exp = 0;
- switch (type) {
- case 'f':
- mode = 3;
- break;
- case 'F':
- exp = 'e';
- mode = 0;
- skip_zeroes = 1;
- type = 'g';
- break;
- case 'e':
- exp = 'e';
- mode = 2;
- precision++; // Add one to include digit before decimal point.
- break;
- case 'E':
- exp = 'E';
- mode = 2;
- precision++; // Add one to include digit before decimal point.
- break;
- case 'g':
- case 'G':
- exp = type == 'g' ? 'e' : 'E';
- if (precision == 0) precision = 1;
- if (!(flags & ios::showpoint))
- skip_zeroes = 1;
- type = 'g';
- mode = 2;
- break;
- }
- /* Do the actual convension */
- char *p = dtoa(value, mode, precision, &decpt, &sign, &end);
- register int i;
- int useful_digits = end-p;
- char *exponent_start = EBUF_END;
- // Check if we need to emit an exponent.
- if (mode != 3 && decpt != 9999) {
- i = decpt - 1;
- if ((type != 'g' && type != 'F') || i < -4 || i >= precision) {
- // Print the exponent into ebuf.
- // We write ebuf in reverse order (right-to-left).
- char sign;
- if (i >= 0)
- sign = '+';
- else
- sign = '-', i = -i;
- /* Note: ANSI requires at least 2 exponent digits. */
- do {
- *--exponent_start = (i % 10) + '0';
- i /= 10;
- } while (i >= 10);
- *--exponent_start = i + '0';
- *--exponent_start = sign;
- *--exponent_start = exp;
- }
- }
- int exponent_size = EBUF_END - exponent_start;
- if (mode == 1)
- precision = 1;
- /* If we print an exponent, always show just one digit before point. */
- if (exponent_size)
- decpt = 1;
- if (decpt == 9999) { // Infinity or NaN
- decpt = useful_digits;
- precision = 0;
- show_dot = 0;
- }
-
- // dtoa truncates trailing zeroes. Set the variable trailing_zeroes to
- // the number of 0's we have to add (after the decimal point).
- int trailing_zeroes = 0;
- if (skip_zeroes)
- trailing_zeroes = 0;
- else if (type == 'f')
- trailing_zeroes = useful_digits <= decpt ? precision
- : precision-(useful_digits-decpt);
- else if (exponent_size) // 'e' 'E' or 'g' format using exponential notation.
- trailing_zeroes = precision - useful_digits;
- else // 'g' format not using exponential notation.
- trailing_zeroes = useful_digits <= decpt ? precision - decpt
- : precision-useful_digits;
- if (trailing_zeroes < 0) trailing_zeroes = 0;
-
- if (trailing_zeroes != 0 || useful_digits > decpt)
- show_dot = 1;
- int print_sign;
- if (sign_mode == 0)
- print_sign = sign ? '-' : 0;
- else if (sign_mode == '+')
- print_sign = sign ? '-' : '+';
- else /* if (sign_mode == ' ') */
- print_sign = sign ? '-' : ' ';
-
- // Calculate the width (before padding).
- int unpadded_width =
- (print_sign != 0) + trailing_zeroes + exponent_size + show_dot
- + useful_digits
- + (decpt > useful_digits ? decpt - useful_digits
- : decpt > 0 ? 0 : 1 - decpt);
-
- int padding = width > unpadded_width ? width - unpadded_width : 0;
- if (padding > 0
- && pad_kind != (ios::fmtflags)ios::left
- && pad_kind != (ios::fmtflags)ios::internal) // Default (right) adjust.
- PADN(fill, padding);
- if (print_sign)
- PUT(print_sign);
- if (pad_kind == (ios::fmtflags)ios::internal && padding > 0)
- PADN(fill, padding);
- if (decpt > 0) {
- if (useful_digits >= decpt)
- PUTN(p, decpt);
- else {
- PUTN(p, useful_digits);
- PADN('0', decpt-useful_digits);
- }
- if (show_dot) {
- PUT('.');
- // Print digits after the decimal point.
- if (useful_digits > decpt)
- PUTN(p + decpt, useful_digits-decpt);
- }
- }
- else {
- PUT('0');
- if (show_dot) {
- PUT('.');
- PADN('0', -decpt);
- // Print digits after the decimal point.
- PUTN(p, useful_digits);
- }
- }
- PADN('0', trailing_zeroes);
- if (exponent_size)
- PUTN(exponent_start, exponent_size);
- if (pad_kind == (ios::fmtflags)ios::left && padding > 0) // Left adjustment
- PADN(fill, padding);
- return count;
- error:
- return EOF;
- }
- #endif
-