OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [newlib/] [newlib/] [libc/] [stdlib/] [ecvtbuf.c] - Blame information for rev 57

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.