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