source: trunk/libs/newlib/src/newlib/libc/stdlib/ecvtbuf.c @ 577

Last change on this file since 577 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 8.4 KB
Line 
1/*
2FUNCTION
3<<ecvtbuf>>, <<fcvtbuf>>---double or float to string
4
5INDEX
6        ecvtbuf
7INDEX
8        fcvtbuf
9
10SYNOPSIS
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
19DESCRIPTION
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
42RETURNS
43        Both functions return a pointer to <[buf]>, the string
44        containing a character representation of <[val]>.
45
46PORTABILITY
47        Neither function is ANSI C.
48
49Supporting 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
60static void
61print_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
127static void
128print_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
209char *
210fcvtbuf (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
265char *
266ecvtbuf (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
315char *
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
422char *
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}
Note: See TracBrowser for help on using the repository browser.