Pristine Ack-5.5
[Ack-5.5.git] / lang / cem / libcc.ansi / stdio / fltpr.c
1 /*
2  * fltpr.c - print floating point numbers
3  */
4 /* $Id: fltpr.c,v 1.6 1994/06/24 11:49:19 ceriel Exp $ */
5
6 #ifndef NOFLOAT
7 #include        <string.h>
8 #include        <stdarg.h>
9 #include        "loc_incl.h"
10
11 static char *
12 _pfloat(long double r, register char *s, int n, int flags)
13 {
14         register char *s1;
15         int sign, dp;
16         register int i;
17
18         s1 = _fcvt(r, n, &dp, &sign);
19         if (sign)
20                 *s++ = '-';
21         else if (flags & FL_SIGN)
22                 *s++ = '+';
23         else if (flags & FL_SPACE)
24                 *s++ = ' ';
25
26         if (dp<=0)
27                 *s++ = '0';
28         for (i=dp; i>0; i--)
29                 if (*s1) *s++ = *s1++;
30                 else *s++ = '0';
31         if (((i=n) > 0) || (flags & FL_ALT))
32                 *s++ = '.';
33         while (++dp <= 0) {
34                 if (--i<0)
35                         break;
36                 *s++ = '0';
37         }
38         while (--i >= 0)
39                 if (*s1) *s++ = *s1++;
40                 else *s++ = '0';
41         return s;
42 }
43
44 static char *
45 _pscien(long double r, register char *s, int n, int flags)
46 {
47         int sign, dp; 
48         register char *s1;
49
50         s1 = _ecvt(r, n + 1, &dp, &sign);
51         if (sign)
52                 *s++ = '-';
53         else if (flags & FL_SIGN)
54                 *s++ = '+';
55         else if (flags & FL_SPACE)
56                 *s++ = ' ';
57
58         *s++ = *s1++;
59         if ((n > 0) || (flags & FL_ALT))
60                 *s++ = '.';
61         while (--n >= 0)
62                 if (*s1) *s++ = *s1++;
63                 else *s++ = '0';
64         *s++ = 'e';
65         if ( r != 0 ) --dp ;
66         if ( dp<0 ) {
67                 *s++ = '-' ; dp= -dp ;
68         } else {
69                 *s++ = '+' ;
70         }
71         if (dp >= 100) {
72                 *s++ = '0' + (dp / 100);
73                 dp %= 100;
74         }
75         *s++ = '0' + (dp/10);
76         *s++ = '0' + (dp%10);
77         return s;
78 }
79
80 #define NDIGINEXP(exp)          (((exp) >= 100 || (exp) <= -100) ? 3 : 2)
81 #define LOW_EXP                 -4
82 #define USE_EXP(exp, ndigits)   (((exp) < LOW_EXP + 1) || (exp >= ndigits + 1))
83
84 static char *
85 _gcvt(long double value, int ndigit, char *s, int flags)
86 {
87         int sign, dp;
88         register char *s1, *s2;
89         register int i;
90         register int nndigit = ndigit;
91
92         s1 = _ecvt(value, ndigit, &dp, &sign);
93         s2 = s;
94         if (sign) *s2++ = '-';
95         else if (flags & FL_SIGN)
96                 *s2++ = '+';
97         else if (flags & FL_SPACE)
98                 *s2++ = ' ';
99
100         if (!(flags & FL_ALT))
101                 for (i = nndigit - 1; i > 0 && s1[i] == '0'; i--)
102                         nndigit--;
103
104         if (USE_EXP(dp,ndigit)) {
105                 /* Use E format */
106                 dp--;
107                 *s2++ = *s1++;
108                 if ((nndigit > 1) || (flags & FL_ALT)) *s2++ = '.';
109                 while (--nndigit > 0) *s2++ = *s1++;
110                 *s2++ = 'e';
111                 if (dp < 0) {
112                         *s2++ = '-';
113                         dp = -dp;
114                 }
115                 else     *s2++ = '+';
116                 s2 += NDIGINEXP(dp);
117                 *s2 = 0;
118                 for (i = NDIGINEXP(dp); i > 0; i--) {
119                         *--s2 = dp % 10 + '0';
120                         dp /= 10;
121                 }
122                 return s;
123         }
124         /* Use f format */
125         if (dp <= 0) {
126                 if (*s1 != '0') {
127                         /* otherwise the whole number is 0 */
128                         *s2++ = '0';
129                         *s2++ = '.';
130                 }
131                 while (dp < 0) {
132                         dp++;
133                         *s2++ = '0';
134                 }
135         }
136         for (i = 1; i <= nndigit; i++) {
137                 *s2++ = *s1++;
138                 if (i == dp) *s2++ = '.';
139         }
140         if (i <= dp) {
141                 while (i++ <= dp) *s2++ = '0';
142                 *s2++ = '.';
143         }
144         if ((s2[-1]=='.') && !(flags & FL_ALT)) s2--;
145         *s2 = '\0';
146         return s;
147 }
148
149 char *
150 _f_print(va_list *ap, int flags, char *s, char c, int precision)
151 {
152         register char *old_s = s;
153         long double ld_val;
154
155         if (flags & FL_LONGDOUBLE) ld_val = va_arg(*ap, long double);
156         else ld_val = (long double) va_arg(*ap, double);
157
158         switch(c) {
159         case 'f':
160                 s = _pfloat(ld_val, s, precision, flags);
161                 break;
162         case 'e':
163         case 'E':
164                 s = _pscien(ld_val, s, precision , flags);
165                 break;
166         case 'g':
167         case 'G':
168                 s = _gcvt(ld_val, precision, s, flags);
169                 s += strlen(s);
170                 break;
171         }
172         if ( c == 'E' || c == 'G') {
173                 while (*old_s && *old_s != 'e') old_s++;
174                 if (*old_s == 'e') *old_s = 'E';
175         }
176         return s;
177 }
178 #endif  /* NOFLOAT */