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 _DEFAULT_SOURCE
58 #include <_ansi.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include "mprec.h"
62 #include "local.h"
63 #include "atexit.h"
64
65 static void
print_f(char * buf,double invalue,int ndigit,char type,int dot,int mode)66 print_f (
67 char *buf,
68 double invalue,
69 int ndigit,
70 char type,
71 int dot,
72 int mode)
73 {
74 int decpt;
75 int sign;
76 char *p, *start, *end;
77
78 (void) type; /* XXX should be used */
79 start = p = __dtoa (invalue, mode, ndigit, &decpt, &sign, &end);
80 if (!p) {
81 buf[0] = '\0';
82 return;
83 }
84
85 if (decpt == 9999)
86 {
87 strcpy (buf, p);
88 return;
89 }
90 while (*p && decpt > 0)
91 {
92 *buf++ = *p++;
93 decpt--;
94 }
95 /* Even if not in buffer */
96 while (decpt > 0)
97 {
98 *buf++ = '0';
99 decpt--;
100 }
101
102 if (dot || *p)
103 {
104 if (p == start)
105 *buf++ = '0';
106 if (decpt < 0 && ndigit > 0)
107 *buf++ = '.';
108 while (decpt < 0 && ndigit > 0)
109 {
110 *buf++ = '0';
111 decpt++;
112 ndigit--;
113 }
114
115 /* Print rest of stuff */
116 while (*p && ndigit > 0)
117 {
118 *buf++ = *p++;
119 ndigit--;
120 }
121 /* And trailing zeros */
122 while (ndigit > 0)
123 {
124 *buf++ = '0';
125 ndigit--;
126 }
127 }
128 *buf++ = 0;
129 }
130
131 /* Print number in e format with width chars after.
132
133 TYPE is one of 'e' or 'E'. It may also be one of 'g' or 'G' indicating
134 that _gcvt is calling us and we should remove trailing zeroes.
135
136 WIDTH is the number of digits of precision after the decimal point. */
137
138 static void
print_e(char * buf,double invalue,int width,char type,int dot)139 print_e (
140 char *buf,
141 double invalue,
142 int width,
143 char type,
144 int dot)
145 {
146 int sign;
147 char *end;
148 char *p;
149 int decpt;
150 int top;
151 int ndigit = width;
152
153 p = __dtoa (invalue, 2, width + 1, &decpt, &sign, &end);
154 if (!p) {
155 buf[0] = '\0';
156 return;
157 }
158
159 if (decpt == 9999)
160 {
161 strcpy (buf, p);
162 return;
163 }
164
165 *buf++ = *p++;
166 if (ndigit > 0)
167 dot = 1;
168
169 while (*p && ndigit > 0)
170 {
171 if (dot) {
172 *buf++ = '.';
173 dot = 0;
174 }
175 *buf++ = *p++;
176 ndigit--;
177 }
178
179 /* Add trailing zeroes to fill out to ndigits unless this is 'g' format.
180 Also, convert g/G to e/E. */
181
182 if (type == 'g')
183 type = 'e';
184 else if (type == 'G')
185 type = 'E';
186 else
187 {
188 while (ndigit > 0)
189 {
190 if (dot) {
191 *buf++ = '.';
192 dot = 0;
193 }
194 *buf++ = '0';
195 ndigit--;
196 }
197 }
198
199 /* Add the exponent. */
200
201 *buf++ = type;
202 decpt--;
203 if (decpt < 0)
204 {
205 *buf++ = '-';
206 decpt = -decpt;
207 }
208 else
209 {
210 *buf++ = '+';
211 }
212 if (decpt > 99)
213 {
214 int top = decpt / 100;
215 *buf++ = top + '0';
216 decpt -= top * 100;
217 }
218 top = decpt / 10;
219 *buf++ = top + '0';
220 decpt -= top * 10;
221 *buf++ = decpt + '0';
222
223 *buf++ = 0;
224 }
225
226 #ifndef _REENT_ONLY
227
228 static NEWLIB_THREAD_LOCAL int _cvtlen;
229 static NEWLIB_THREAD_LOCAL char *_cvtbuf;
230
231 static void
_cvtcleanup(void)232 _cvtcleanup(void)
233 {
234 if (_cvtbuf) {
235 free(_cvtbuf);
236 _cvtbuf = NULL;
237 }
238 }
239
240 /* Undocumented behaviour: when given NULL as a buffer, return a
241 pointer to static space in the rent structure. This is only to
242 support ecvt and fcvt, which aren't ANSI anyway. */
243
244 char *
fcvtbuf(double invalue,int ndigit,int * decpt,int * sign,char * fcvt_buf)245 fcvtbuf (double invalue,
246 int ndigit,
247 int *decpt,
248 int *sign,
249 char *fcvt_buf)
250 {
251 char *save;
252 char *p;
253 char *end;
254 int done = 0;
255
256 if (fcvt_buf == NULL)
257 {
258 if (_cvtlen <= ndigit + 35)
259 {
260 if (!_cvtbuf)
261 if (atexit(_cvtcleanup) != 0)
262 return NULL;
263 if ((fcvt_buf = (char *) realloc (_cvtbuf,
264 ndigit + 36)) == NULL)
265 return NULL;
266 _cvtlen = ndigit + 36;
267 _cvtbuf = fcvt_buf;
268 }
269
270 fcvt_buf = _cvtbuf ;
271 }
272
273 save = fcvt_buf;
274
275 p = __dtoa (invalue, 3, ndigit, decpt, sign, &end);
276 if (!p)
277 return NULL;
278
279 /* Now copy */
280
281 done = -*decpt;
282
283 while (p < end)
284 {
285 *fcvt_buf++ = *p++;
286 done++;
287 }
288 /* And unsuppress the trailing zeroes */
289 while (done < ndigit)
290 {
291 *fcvt_buf++ = '0';
292 done++;
293 }
294 *fcvt_buf++ = 0;
295 return save;
296 }
297
298 char *
ecvtbuf(double invalue,int ndigit,int * decpt,int * sign,char * fcvt_buf)299 ecvtbuf (double invalue,
300 int ndigit,
301 int *decpt,
302 int *sign,
303 char *fcvt_buf)
304 {
305 char *save;
306 char *p;
307 char *end;
308 int done = 0;
309
310 if (fcvt_buf == NULL)
311 {
312 if (_cvtlen <= ndigit)
313 {
314 if ((fcvt_buf = (char *) realloc (_cvtbuf,
315 ndigit + 1)) == NULL)
316 return NULL;
317 _cvtlen = ndigit + 1;
318 _cvtbuf = fcvt_buf;
319 }
320
321 fcvt_buf = _cvtbuf ;
322 }
323
324 save = fcvt_buf;
325
326 p = __dtoa (invalue, 2, ndigit, decpt, sign, &end);
327 if (!p)
328 return NULL;
329
330 /* Now copy */
331
332 while (p < end)
333 {
334 *fcvt_buf++ = *p++;
335 done++;
336 }
337 /* And unsuppress the trailing zeroes */
338 while (done < ndigit)
339 {
340 *fcvt_buf++ = '0';
341 done++;
342 }
343 *fcvt_buf++ = 0;
344 return save;
345 }
346
347 #endif
348
349 char *
_gcvt(double invalue,int ndigit,char * buf,char type,int dot)350 _gcvt (
351 double invalue,
352 int ndigit,
353 char *buf,
354 char type,
355 int dot)
356 {
357 char *save = buf;
358
359 if (invalue < 0)
360 {
361 invalue = -invalue;
362 }
363
364 if (invalue == 0)
365 {
366 *buf++ = '0';
367 *buf = '\0';
368 }
369 else
370 /* Which one to print ?
371 ANSI says that anything with more that 4 zeros after the . or more
372 than precision digits before is printed in e with the qualification
373 that trailing zeroes are removed from the fraction portion. */
374
375 if (0.0001 >= invalue || invalue >= _mprec_log10 (ndigit))
376 {
377 /* We subtract 1 from ndigit because in the 'e' format the precision is
378 the number of digits after the . but in 'g' format it is the number
379 of significant digits.
380
381 We defer changing type to e/E so that print_e() can know it's us
382 calling and thus should remove trailing zeroes. */
383
384 print_e (buf, invalue, ndigit - 1, type, dot);
385 }
386 else
387 {
388 int decpt;
389 int sign;
390 char *end;
391 char *p;
392
393 /* We always want ndigits of precision, even if that means printing
394 * a bunch of leading zeros for numbers < 1.0
395 */
396 p = __dtoa (invalue, 2, ndigit, &decpt, &sign, &end);
397 if (!p)
398 return NULL;
399
400 if (decpt == 9999)
401 {
402 strcpy (buf, p);
403 return save;
404 }
405 while (*p && decpt > 0)
406 {
407 *buf++ = *p++;
408 decpt--;
409 ndigit--;
410 }
411 /* Even if not in buffer */
412 while (decpt > 0 && ndigit > 0)
413 {
414 *buf++ = '0';
415 decpt--;
416 ndigit--;
417 }
418
419 if (dot || *p)
420 {
421 if (buf == save)
422 *buf++ = '0';
423 *buf++ = '.';
424
425 /* Leading zeros don't count towards 'ndigit' */
426 while (decpt < 0)
427 {
428 *buf++ = '0';
429 decpt++;
430 }
431
432 /* Print rest of stuff */
433 while (*p && ndigit > 0)
434 {
435 *buf++ = *p++;
436 ndigit--;
437 }
438 /* And trailing zeros */
439 if (dot)
440 {
441 while (ndigit > 0)
442 {
443 *buf++ = '0';
444 ndigit--;
445 }
446 }
447 }
448 *buf++ = 0;
449 }
450
451 return save;
452 }
453
454 char *
_dcvt(char * buffer,double invalue,int precision,int width,char type,int dot)455 _dcvt (
456 char *buffer,
457 double invalue,
458 int precision,
459 int width,
460 char type,
461 int dot)
462 {
463 (void) width; /* XXX should be used */
464 switch (type)
465 {
466 case 'f':
467 case 'F':
468 print_f (buffer, invalue, precision, type, precision == 0 ? dot : 1, 3);
469 break;
470 case 'g':
471 case 'G':
472 if (precision == 0)
473 precision = 1;
474 _gcvt (invalue, precision, buffer, type, dot);
475 break;
476 case 'e':
477 case 'E':
478 print_e (buffer, invalue, precision, type, dot);
479 }
480 return buffer;
481 }
482