1 /*
2 Copyright (c) 1990 Regents of the University of California.
3 All rights reserved.
4 */
5 /*
6 FUNCTION
7 <<ecvtbuf>>, <<fcvtbuf>>---double or float to string
8
9 INDEX
10 ecvtbuf
11 INDEX
12 fcvtbuf
13
14 SYNOPSIS
15 #include <stdio.h>
16
17 char *ecvtbuf(double <[val]>, int <[chars]>, int *<[decpt]>,
18 int *<[sgn]>, char *<[buf]>);
19
20 char *fcvtbuf(double <[val]>, int <[decimals]>, int *<[decpt]>,
21 int *<[sgn]>, char *<[buf]>);
22
23 DESCRIPTION
24 <<ecvtbuf>> and <<fcvtbuf>> produce (null-terminated) strings
25 of digits representating the <<double>> number <[val]>.
26
27 The only difference between <<ecvtbuf>> and <<fcvtbuf>> is the
28 interpretation of the second argument (<[chars]> or
29 <[decimals]>). For <<ecvtbuf>>, the second argument <[chars]>
30 specifies the total number of characters to write (which is
31 also the number of significant digits in the formatted string,
32 since these two functions write only digits). For <<fcvtbuf>>,
33 the second argument <[decimals]> specifies the number of
34 characters to write after the decimal point; all digits for
35 the integer part of <[val]> are always included.
36
37 Since <<ecvtbuf>> and <<fcvtbuf>> write only digits in the
38 output string, they record the location of the decimal point
39 in <<*<[decpt]>>>, and the sign of the number in <<*<[sgn]>>>.
40 After formatting a number, <<*<[decpt]>>> contains the number
41 of digits to the left of the decimal point. <<*<[sgn]>>>
42 contains <<0>> if the number is positive, and <<1>> if it is
43 negative. For both functions, you supply a pointer <[buf]> to
44 an area of memory to hold the converted string.
45
46 RETURNS
47 Both functions return a pointer to <[buf]>, the string
48 containing a character representation of <[val]>.
49
50 PORTABILITY
51 Neither function is ANSI C.
52
53 Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
54 <<lseek>>, <<read>>, <<sbrk>>, <<write>>.
55 */
56
57 #define _GNU_SOURCE
58 #include <stdlib.h>
59 #include <string.h>
60 #include "mprec.h"
61 #include "local.h"
62 #include "atexit.h"
63
64 /* Print number in e format with width chars after.
65
66 TYPE is one of 'e' or 'E'. It may also be one of 'g' or 'G' indicating
67 that _gcvt is calling us and we should remove trailing zeroes.
68
69 WIDTH is the number of digits of precision after the decimal point. */
70
71 static void
print_e(char * buf,double invalue,int width,char type,int dot)72 print_e (
73 char *buf,
74 double invalue,
75 int width,
76 char type,
77 int dot)
78 {
79 int sign;
80 char *end;
81 char *p;
82 int decpt;
83 int top;
84 int ndigit = width;
85
86 p = __dtoa (invalue, 2, width + 1, &decpt, &sign, &end);
87 if (!p) {
88 buf[0] = '\0';
89 return;
90 }
91
92 if (decpt == 9999)
93 {
94 strcpy (buf, p);
95 return;
96 }
97
98 *buf++ = *p++;
99 if (ndigit > 0)
100 dot = 1;
101
102 while (*p && ndigit > 0)
103 {
104 if (dot) {
105 *buf++ = '.';
106 dot = 0;
107 }
108 *buf++ = *p++;
109 ndigit--;
110 }
111
112 /* Add trailing zeroes to fill out to ndigits unless this is 'g' format.
113 Also, convert g/G to e/E. */
114
115 if (type == 'g')
116 type = 'e';
117 else if (type == 'G')
118 type = 'E';
119 else
120 {
121 while (ndigit > 0)
122 {
123 if (dot) {
124 *buf++ = '.';
125 dot = 0;
126 }
127 *buf++ = '0';
128 ndigit--;
129 }
130 }
131
132 /* Add the exponent. */
133
134 *buf++ = type;
135 decpt--;
136 if (decpt < 0)
137 {
138 *buf++ = '-';
139 decpt = -decpt;
140 }
141 else
142 {
143 *buf++ = '+';
144 }
145 if (decpt > 99)
146 {
147 int top = decpt / 100;
148 *buf++ = top + '0';
149 decpt -= top * 100;
150 }
151 top = decpt / 10;
152 *buf++ = top + '0';
153 decpt -= top * 10;
154 *buf++ = decpt + '0';
155
156 *buf++ = 0;
157 }
158
159 #ifndef _REENT_ONLY
160
161 static NEWLIB_THREAD_LOCAL int _cvtlen;
162 static NEWLIB_THREAD_LOCAL char *_cvtbuf;
163
164 static void
_cvtcleanup(void)165 _cvtcleanup(void)
166 {
167 if (_cvtbuf) {
168 free(_cvtbuf);
169 _cvtbuf = NULL;
170 }
171 }
172
173 /* Undocumented behaviour: when given NULL as a buffer, return a
174 pointer to static space in the rent structure. This is only to
175 support ecvt and fcvt, which aren't ANSI anyway. */
176
177 char *
fcvtbuf(double invalue,int ndigit,int * decpt,int * sign,char * fcvt_buf)178 fcvtbuf (double invalue,
179 int ndigit,
180 int *decpt,
181 int *sign,
182 char *fcvt_buf)
183 {
184 char *save;
185 char *p;
186 char *end;
187 int done = 0;
188
189 if (fcvt_buf == NULL)
190 {
191 if (_cvtlen <= ndigit + 35)
192 {
193 if (!_cvtbuf)
194 if (atexit(_cvtcleanup) != 0)
195 return NULL;
196 if ((fcvt_buf = (char *) realloc (_cvtbuf,
197 ndigit + 36)) == NULL)
198 return NULL;
199 _cvtlen = ndigit + 36;
200 _cvtbuf = fcvt_buf;
201 }
202
203 fcvt_buf = _cvtbuf ;
204 }
205
206 save = fcvt_buf;
207
208 p = __dtoa (invalue, 3, ndigit, decpt, sign, &end);
209 if (!p)
210 return NULL;
211
212 if (*decpt == 9999)
213 {
214 strcpy(fcvt_buf, p);
215 return fcvt_buf;
216 }
217
218 /* Now copy */
219
220 done = -*decpt;
221
222 while (p < end)
223 {
224 *fcvt_buf++ = *p++;
225 done++;
226 }
227 /* And unsuppress the trailing zeroes */
228 while (done < ndigit)
229 {
230 *fcvt_buf++ = '0';
231 done++;
232 }
233 *fcvt_buf++ = 0;
234 return save;
235 }
236
237 char *
ecvtbuf(double invalue,int ndigit,int * decpt,int * sign,char * fcvt_buf)238 ecvtbuf (double invalue,
239 int ndigit,
240 int *decpt,
241 int *sign,
242 char *fcvt_buf)
243 {
244 char *save;
245 char *p;
246 char *end;
247 int done = 0;
248
249 if (fcvt_buf == NULL)
250 {
251 if (_cvtlen <= ndigit)
252 {
253 if ((fcvt_buf = (char *) realloc (_cvtbuf,
254 ndigit + 1)) == NULL)
255 return NULL;
256 _cvtlen = ndigit + 1;
257 _cvtbuf = fcvt_buf;
258 }
259
260 fcvt_buf = _cvtbuf ;
261 }
262
263 save = fcvt_buf;
264
265 p = __dtoa (invalue, 2, ndigit, decpt, sign, &end);
266 if (!p)
267 return NULL;
268
269 if (*decpt == 9999)
270 {
271 strcpy(fcvt_buf, p);
272 return fcvt_buf;
273 }
274
275 /* Now copy */
276
277 while (p < end)
278 {
279 *fcvt_buf++ = *p++;
280 done++;
281 }
282 /* And unsuppress the trailing zeroes */
283 while (done < ndigit)
284 {
285 *fcvt_buf++ = '0';
286 done++;
287 }
288 *fcvt_buf++ = 0;
289 return save;
290 }
291
292 #endif
293
294 char *
_gcvt(double invalue,int ndigit,char * buf,char type,int dot)295 _gcvt (
296 double invalue,
297 int ndigit,
298 char *buf,
299 char type,
300 int dot)
301 {
302 char *save = buf;
303
304 if (invalue < 0)
305 {
306 invalue = -invalue;
307 }
308
309 if (invalue == 0)
310 {
311 *buf++ = '0';
312 *buf = '\0';
313 }
314 else
315 /* Which one to print ?
316 ANSI says that anything with more that 4 zeros after the . or more
317 than precision digits before is printed in e with the qualification
318 that trailing zeroes are removed from the fraction portion. */
319
320 if (0.0001 >= invalue || invalue >= _mprec_log10 (ndigit))
321 {
322 /* We subtract 1 from ndigit because in the 'e' format the precision is
323 the number of digits after the . but in 'g' format it is the number
324 of significant digits.
325
326 We defer changing type to e/E so that print_e() can know it's us
327 calling and thus should remove trailing zeroes. */
328
329 print_e (buf, invalue, ndigit - 1, type, dot);
330 }
331 else
332 {
333 int decpt;
334 int sign;
335 char *end;
336 char *p;
337
338 /* We always want ndigits of precision, even if that means printing
339 * a bunch of leading zeros for numbers < 1.0
340 */
341 p = __dtoa (invalue, 2, ndigit, &decpt, &sign, &end);
342 if (!p)
343 return NULL;
344
345 if (decpt == 9999)
346 {
347 strcpy (buf, p);
348 return save;
349 }
350 while (*p && decpt > 0)
351 {
352 *buf++ = *p++;
353 decpt--;
354 ndigit--;
355 }
356 /* Even if not in buffer */
357 while (decpt > 0 && ndigit > 0)
358 {
359 *buf++ = '0';
360 decpt--;
361 ndigit--;
362 }
363
364 if (dot || *p)
365 {
366 if (buf == save)
367 *buf++ = '0';
368 *buf++ = '.';
369
370 /* Leading zeros don't count towards 'ndigit' */
371 while (decpt < 0)
372 {
373 *buf++ = '0';
374 decpt++;
375 }
376
377 /* Print rest of stuff */
378 while (*p && ndigit > 0)
379 {
380 *buf++ = *p++;
381 ndigit--;
382 }
383 /* And trailing zeros */
384 if (dot)
385 {
386 while (ndigit > 0)
387 {
388 *buf++ = '0';
389 ndigit--;
390 }
391 }
392 }
393 *buf++ = 0;
394 }
395
396 return save;
397 }
398