Cygwin: mmap: allow remapping part of an existing anonymous mapping
[newlib-cygwin.git] / newlib / libc / stdlib / ecvtbuf.c
blob514896682593c0b99ac71336ae9823d8e7d47772
1 /*
2 FUNCTION
3 <<ecvtbuf>>, <<fcvtbuf>>---double or float to string
5 INDEX
6 ecvtbuf
7 INDEX
8 fcvtbuf
10 SYNOPSIS
11 #include <stdio.h>
13 char *ecvtbuf(double <[val]>, int <[chars]>, int *<[decpt]>,
14 int *<[sgn]>, char *<[buf]>);
16 char *fcvtbuf(double <[val]>, int <[decimals]>, int *<[decpt]>,
17 int *<[sgn]>, char *<[buf]>);
19 DESCRIPTION
20 <<ecvtbuf>> and <<fcvtbuf>> produce (null-terminated) strings
21 of digits representating the <<double>> number <[val]>.
23 The only difference between <<ecvtbuf>> and <<fcvtbuf>> is the
24 interpretation of the second argument (<[chars]> or
25 <[decimals]>). For <<ecvtbuf>>, the second argument <[chars]>
26 specifies the total number of characters to write (which is
27 also the number of significant digits in the formatted string,
28 since these two functions write only digits). For <<fcvtbuf>>,
29 the second argument <[decimals]> specifies the number of
30 characters to write after the decimal point; all digits for
31 the integer part of <[val]> are always included.
33 Since <<ecvtbuf>> and <<fcvtbuf>> write only digits in the
34 output string, they record the location of the decimal point
35 in <<*<[decpt]>>>, and the sign of the number in <<*<[sgn]>>>.
36 After formatting a number, <<*<[decpt]>>> contains the number
37 of digits to the left of the decimal point. <<*<[sgn]>>>
38 contains <<0>> if the number is positive, and <<1>> if it is
39 negative. For both functions, you supply a pointer <[buf]> to
40 an area of memory to hold the converted string.
42 RETURNS
43 Both functions return a pointer to <[buf]>, the string
44 containing a character representation of <[val]>.
46 PORTABILITY
47 Neither function is ANSI C.
49 Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
50 <<lseek>>, <<read>>, <<sbrk>>, <<write>>.
53 #include <_ansi.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <reent.h>
57 #include "mprec.h"
58 #include "local.h"
60 #ifdef _REENT_THREAD_LOCAL
61 _Thread_local char *_tls_cvtbuf;
62 _Thread_local int _tls_cvtlen;
63 #endif
65 static void
66 print_f (struct _reent *ptr,
67 char *buf,
68 double invalue,
69 int ndigit,
70 char type,
71 int dot,
72 int mode)
74 int decpt;
75 int sign;
76 char *p, *start, *end;
78 start = p = _dtoa_r (ptr, invalue, mode, ndigit, &decpt, &sign, &end);
80 if (decpt == 9999)
82 strcpy (buf, p);
83 return;
85 while (*p && decpt > 0)
87 *buf++ = *p++;
88 decpt--;
90 /* Even if not in buffer */
91 while (decpt > 0)
93 *buf++ = '0';
94 decpt--;
97 if (dot || *p)
99 if (p == start)
100 *buf++ = '0';
101 if (decpt < 0 && ndigit > 0)
102 *buf++ = '.';
103 while (decpt < 0 && ndigit > 0)
105 *buf++ = '0';
106 decpt++;
107 ndigit--;
110 /* Print rest of stuff */
111 while (*p && ndigit > 0)
113 *buf++ = *p++;
114 ndigit--;
116 /* And trailing zeros */
117 while (ndigit > 0)
119 *buf++ = '0';
120 ndigit--;
123 *buf++ = 0;
126 /* Print number in e format with width chars after.
128 TYPE is one of 'e' or 'E'. It may also be one of 'g' or 'G' indicating
129 that _gcvt is calling us and we should remove trailing zeroes.
131 WIDTH is the number of digits of precision after the decimal point. */
133 static void
134 print_e (struct _reent *ptr,
135 char *buf,
136 double invalue,
137 int width,
138 char type,
139 int dot)
141 int sign;
142 char *end;
143 char *p;
144 int decpt;
145 int top;
146 int ndigit = width;
148 p = _dtoa_r (ptr, invalue, 2, width + 1, &decpt, &sign, &end);
150 if (decpt == 9999)
152 strcpy (buf, p);
153 return;
156 *buf++ = *p++;
157 if (ndigit > 0)
158 dot = 1;
160 while (*p && ndigit > 0)
162 if (dot) {
163 *buf++ = '.';
164 dot = 0;
166 *buf++ = *p++;
167 ndigit--;
170 /* Add trailing zeroes to fill out to ndigits unless this is 'g' format.
171 Also, convert g/G to e/E. */
173 if (type == 'g')
174 type = 'e';
175 else if (type == 'G')
176 type = 'E';
177 else
179 while (ndigit > 0)
181 if (dot) {
182 *buf++ = '.';
183 dot = 0;
185 *buf++ = '0';
186 ndigit--;
190 /* Add the exponent. */
192 *buf++ = type;
193 decpt--;
194 if (decpt < 0)
196 *buf++ = '-';
197 decpt = -decpt;
199 else
201 *buf++ = '+';
203 if (decpt > 99)
205 int top = decpt / 100;
206 *buf++ = top + '0';
207 decpt -= top * 100;
209 top = decpt / 10;
210 *buf++ = top + '0';
211 decpt -= top * 10;
212 *buf++ = decpt + '0';
214 *buf++ = 0;
217 #ifndef _REENT_ONLY
219 /* Undocumented behaviour: when given NULL as a buffer, return a
220 pointer to static space in the rent structure. This is only to
221 support ecvt and fcvt, which aren't ANSI anyway. */
223 char *
224 fcvtbuf (double invalue,
225 int ndigit,
226 int *decpt,
227 int *sign,
228 char *fcvt_buf)
230 struct _reent *reent = _REENT;
231 char *save;
232 char *p;
233 char *end;
234 int done = 0;
236 if (fcvt_buf == NULL)
238 if (_REENT_CVTLEN(reent) <= ndigit + 35)
240 if ((fcvt_buf = (char *) _realloc_r (reent, _REENT_CVTBUF(reent),
241 ndigit + 36)) == NULL)
242 return NULL;
243 _REENT_CVTLEN(reent) = ndigit + 36;
244 _REENT_CVTBUF(reent) = fcvt_buf;
247 fcvt_buf = _REENT_CVTBUF(reent) ;
250 save = fcvt_buf;
252 p = _dtoa_r (reent, invalue, 3, ndigit, decpt, sign, &end);
254 /* Now copy */
256 done = -*decpt;
257 while (p < end)
259 *fcvt_buf++ = *p++;
260 done++;
262 /* And unsuppress the trailing zeroes */
263 while (done < ndigit)
265 *fcvt_buf++ = '0';
266 done++;
268 *fcvt_buf++ = 0;
269 return save;
272 char *
273 ecvtbuf (double invalue,
274 int ndigit,
275 int *decpt,
276 int *sign,
277 char *fcvt_buf)
279 struct _reent *reent = _REENT;
280 char *save;
281 char *p;
282 char *end;
283 int done = 0;
285 if (fcvt_buf == NULL)
287 if (_REENT_CVTLEN(reent) <= ndigit)
289 if ((fcvt_buf = (char *) _realloc_r (reent, _REENT_CVTBUF(reent),
290 ndigit + 1)) == NULL)
291 return NULL;
292 _REENT_CVTLEN(reent) = ndigit + 1;
293 _REENT_CVTBUF(reent) = fcvt_buf;
296 fcvt_buf = _REENT_CVTBUF(reent) ;
299 save = fcvt_buf;
301 p = _dtoa_r (reent, invalue, 2, ndigit, decpt, sign, &end);
303 /* Now copy */
305 while (p < end)
307 *fcvt_buf++ = *p++;
308 done++;
310 /* And unsuppress the trailing zeroes */
311 while (done < ndigit)
313 *fcvt_buf++ = '0';
314 done++;
316 *fcvt_buf++ = 0;
317 return save;
320 #endif
322 char *
323 _gcvt (struct _reent *ptr,
324 double invalue,
325 int ndigit,
326 char *buf,
327 char type,
328 int dot)
330 char *save = buf;
332 if (invalue < 0)
334 invalue = -invalue;
337 if (invalue == 0)
339 *buf++ = '0';
340 *buf = '\0';
342 else
343 /* Which one to print ?
344 ANSI says that anything with more that 4 zeros after the . or more
345 than precision digits before is printed in e with the qualification
346 that trailing zeroes are removed from the fraction portion. */
348 if (0.0001 >= invalue || invalue >= _mprec_log10 (ndigit))
350 /* We subtract 1 from ndigit because in the 'e' format the precision is
351 the number of digits after the . but in 'g' format it is the number
352 of significant digits.
354 We defer changing type to e/E so that print_e() can know it's us
355 calling and thus should remove trailing zeroes. */
357 print_e (ptr, buf, invalue, ndigit - 1, type, dot);
359 else
361 int decpt;
362 int sign;
363 char *end;
364 char *p;
366 /* We always want ndigits of precision, even if that means printing
367 * a bunch of leading zeros for numbers < 1.0
369 p = _dtoa_r (ptr, invalue, 2, ndigit, &decpt, &sign, &end);
371 if (decpt == 9999)
373 strcpy (buf, p);
374 return save;
376 while (*p && decpt > 0)
378 *buf++ = *p++;
379 decpt--;
380 ndigit--;
382 /* Even if not in buffer */
383 while (decpt > 0 && ndigit > 0)
385 *buf++ = '0';
386 decpt--;
387 ndigit--;
390 if (dot || *p)
392 if (buf == save)
393 *buf++ = '0';
394 *buf++ = '.';
396 /* Leading zeros don't count towards 'ndigit' */
397 while (decpt < 0)
399 *buf++ = '0';
400 decpt++;
403 /* Print rest of stuff */
404 while (*p && ndigit > 0)
406 *buf++ = *p++;
407 ndigit--;
409 /* And trailing zeros */
410 if (dot)
412 while (ndigit > 0)
414 *buf++ = '0';
415 ndigit--;
419 *buf++ = 0;
422 return save;
425 char *
426 _dcvt (struct _reent *ptr,
427 char *buffer,
428 double invalue,
429 int precision,
430 int width,
431 char type,
432 int dot)
434 switch (type)
436 case 'f':
437 case 'F':
438 print_f (ptr, buffer, invalue, precision, type, precision == 0 ? dot : 1, 3);
439 break;
440 case 'g':
441 case 'G':
442 if (precision == 0)
443 precision = 1;
444 _gcvt (ptr, invalue, precision, buffer, type, dot);
445 break;
446 case 'e':
447 case 'E':
448 print_e (ptr, buffer, invalue, precision, type, dot);
450 return buffer;