Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / contrib / libio / outfloat.c
1 /* 
2 Copyright (C) 1993 Free Software Foundation
3
4 This file is part of the GNU IO Library.  This library is free
5 software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this library; see the file COPYING.  If not, write to the Free
17 Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 As a special exception, if you link this library with files
20 compiled with a GNU compiler to produce an executable, this does not cause
21 the resulting executable to be covered by the GNU General Public License.
22 This exception does not however invalidate any other reasons why
23 the executable file might be covered by the GNU General Public License. */
24
25 #include "libioP.h"
26
27 #ifdef _IO_USE_DTOA
28 /* Format floating-point number and print them.
29    Return number of chars printed, or EOF on error.
30
31    sign_mode == '+' : print "-" or "+"
32    sign_mode == ' ' : print "-" or " "
33    sign_mode == '\0' : print "-' or ""
34 */
35
36 int
37 _IO_outfloat (value, sb, type, width, precision, flags, sign_mode, fill)
38      double value;
39      _IO_FILE *sb;
40      int type;
41      int width;
42      int precision;
43      int flags;
44      int sign_mode;
45      int fill;
46 {
47   int count = 0;
48 #define PUT(x) do {if (_IO_putc(x, sb) < 0) goto error; count++;} while (0)
49 #define PUTN(p, n) \
50   do {int _n=n; count+=_n; if (_IO_sputn(sb, p,_n) != _n) goto error;} while(0)
51 #define PADN(fill, n) \
52   do {int _n = n; count+=_n; if (_IO_padn(sb, fill, _n) != _n) goto error;} while (0)
53   int pad_kind = flags & (_IO_LEFT|_IO_RIGHT|_IO_INTERNAL);
54   int skip_zeroes = 0;
55   int show_dot = (flags & _IO_SHOWPOINT) != 0;
56   int decpt;
57   int sign;
58   int mode;
59   int exponent_size;
60   int print_sign;
61   int trailing_zeroes, useful_digits;
62   int padding, unpadded_width;
63   char *p;
64   char *exponent_start;
65   register int i;
66 #define EBUF_SIZE 12
67 #define EBUF_END &ebuf[EBUF_SIZE]
68   char ebuf[EBUF_SIZE];
69   char *end;
70   int exp = 0;
71   switch (type)
72     {
73     case 'f':
74       mode = 3;
75       break;
76     case 'e':
77     case 'E':
78       exp = type;
79       mode = 2;
80       if (precision != 999)
81         precision++;  /* Add one to include digit before decimal point. */
82       break;
83     case 'g':
84     case 'G':
85       exp = type == 'g' ? 'e' : 'E';
86       if (precision == 0) precision = 1;
87       if (!(flags & _IO_SHOWPOINT))
88         skip_zeroes = 1;
89       type = 'g';
90       mode = 2;
91       break;
92     }
93   /* Do the actual convension */
94   if (precision == 999 && mode != 3)
95     mode = 0;
96   p = _IO_dtoa(value, mode, precision, &decpt, &sign, &end);
97   useful_digits = end-p;
98   exponent_start = EBUF_END;
99   if (mode == 0)
100     precision = useful_digits;
101   /* Check if we need to emit an exponent. */
102   if (mode != 3 && decpt != 9999)
103     {
104       i = decpt - 1;
105       if ((type != 'g' && type != 'F') || i < -4 || i >= precision)
106         {
107           /* Print the exponent into ebuf.
108              We write ebuf in reverse order (right-to-left). */
109           char sign;
110           if (i >= 0)
111             sign = '+';
112           else
113             sign = '-', i = -i;
114           /* Note: ANSI requires at least 2 exponent digits. */
115           do {
116             *--exponent_start = (i % 10) + '0';
117             i /= 10;
118           } while (i >= 10);
119           *--exponent_start = i + '0';
120           *--exponent_start = sign;
121           *--exponent_start = exp;
122         }
123     }
124   exponent_size = EBUF_END - exponent_start;
125   if (mode == 1)
126     precision = 1;
127   /* If we print an exponent, always show just one digit before point. */
128   if (exponent_size)
129     decpt = 1;
130   if (decpt == 9999)
131     { /* Infinity or NaN */
132       decpt = useful_digits;
133       precision = 0;
134       show_dot = 0;
135     }
136   
137   /* dtoa truncates trailing zeroes.  Set the variable trailing_zeroes to
138      the number of 0's we have to add (after the decimal point). */
139   if (skip_zeroes)
140     trailing_zeroes = 0;
141   else if (type == 'f')
142     trailing_zeroes = useful_digits <= decpt ? precision
143       : precision-(useful_digits-decpt);
144   else if (exponent_size) /* 'e' 'E' or 'g' format using exponential notation*/
145     trailing_zeroes = precision - useful_digits;
146   else /* 'g' format not using exponential notation. */
147     trailing_zeroes = useful_digits <= decpt ? precision - decpt
148       : precision-useful_digits;
149   if (trailing_zeroes < 0) trailing_zeroes = 0;
150   
151   if (trailing_zeroes != 0 || useful_digits > decpt)
152     show_dot = 1;
153   if (sign_mode == 0)
154     print_sign = sign ? '-' : 0;
155   else if (sign_mode == '+')
156     print_sign = sign ? '-' : '+';
157   else /* if (sign_mode == ' ') */
158     print_sign = sign ? '-' : ' ';
159   
160   /* Calculate the width (before padding). */
161   unpadded_width =
162     (print_sign != 0) + trailing_zeroes + exponent_size + show_dot
163       + useful_digits
164         + (decpt > useful_digits ? decpt - useful_digits
165            : decpt > 0 ? 0 : 1 - decpt);
166   
167   padding = width > unpadded_width ? width - unpadded_width : 0;
168   if (padding > 0 && pad_kind != _IO_LEFT && pad_kind != _IO_INTERNAL)
169     PADN(fill, padding); /* Default (right) adjust */
170   if (print_sign)
171     PUT(print_sign);
172   if (pad_kind == _IO_INTERNAL && padding > 0)
173     PADN(fill, padding);
174   if (decpt > 0)
175     {
176       if (useful_digits >= decpt)
177         PUTN(p, decpt);
178       else
179         {
180           PUTN(p, useful_digits);
181           PADN('0', decpt-useful_digits);
182         }
183       if (show_dot)
184         {
185           PUT('.');
186           /* Print digits after the decimal point. */
187           if (useful_digits > decpt)
188             PUTN(p + decpt, useful_digits-decpt);
189         }
190     }
191   else
192     {
193       PUT('0');
194       if (show_dot)
195         {
196           PUT('.');
197           PADN('0', -decpt);
198           /* Print digits after the decimal point. */
199           PUTN(p, useful_digits);
200         }
201     }
202   PADN('0', trailing_zeroes);
203   if (exponent_size)
204     PUTN(exponent_start, exponent_size);
205   if (pad_kind == _IO_LEFT && padding > 0) /* Left adjustment*/
206     PADN(fill, padding);
207   return count;
208  error:
209   return EOF;
210 }
211 #endif