source: trunk/libs/newlib/src/newlib/libc/stdio/nano-vfprintf_float.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: 9.0 KB
Line 
1/*
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Chris Torek.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <newlib.h>
34
35#include <_ansi.h>
36#include <reent.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <limits.h>
41#include <stdint.h>
42#include <wchar.h>
43#include <sys/lock.h>
44#include <stdarg.h>
45#include "local.h"
46#include "../stdlib/local.h"
47#include "fvwrite.h"
48#include "vfieeefp.h"
49#include "nano-vfprintf_local.h"
50
51char *__cvt (struct _reent *data, _PRINTF_FLOAT_TYPE value, int ndigits,
52             int flags, char *sign, int *decpt, int ch, int *length,
53             char *buf);
54
55int __exponent (char *p0, int exp, int fmtch);
56
57#ifdef FLOATING_POINT
58
59/* Using reentrant DATA, convert finite VALUE into a string of digits
60   with no decimal point, using NDIGITS precision and FLAGS as guides
61   to whether trailing zeros must be included.  Set *SIGN to nonzero
62   if VALUE was negative.  Set *DECPT to the exponent plus one.  Set
63   *LENGTH to the length of the returned string.  CH must be one of
64   [aAeEfFgG]; if it is [aA], then the return string lives in BUF,
65   otherwise the return value shares the mprec reentrant storage.  */
66char *
67__cvt (struct _reent *data, _PRINTF_FLOAT_TYPE value, int ndigits, int flags,
68       char *sign, int *decpt, int ch, int *length, char *buf)
69{
70  int mode, dsgn;
71  char *digits, *bp, *rve;
72  union double_union tmp;
73
74  tmp.d = value;
75  /* This will check for "< 0" and "-0.0".  */
76  if (word0 (tmp) & Sign_bit)
77    {
78      value = -value;
79      *sign = '-';
80    }
81  else
82    *sign = '\000';
83
84  if (ch == 'f' || ch == 'F')
85    {
86      /* Ndigits after the decimal point.  */
87      mode = 3;
88    }
89  else
90    {
91      /* To obtain ndigits after the decimal point for the 'e'
92         and 'E' formats, round to ndigits + 1 significant figures.  */
93      if (ch == 'e' || ch == 'E')
94        {
95          ndigits++;
96        }
97      /* Ndigits significant digits.  */
98      mode = 2;
99    }
100
101  digits = _DTOA_R (data, value, mode, ndigits, decpt, &dsgn, &rve);
102
103  /* Print trailing zeros.  */
104  if ((ch != 'g' && ch != 'G') || flags & ALT)
105    {
106      bp = digits + ndigits;
107      if (ch == 'f' || ch == 'F')
108        {
109          if (*digits == '0' && value)
110            *decpt = -ndigits + 1;
111          bp += *decpt;
112        }
113      /* Kludge for __dtoa irregularity.  */
114      if (value == 0)
115        rve = bp;
116      while (rve < bp)
117        *rve++ = '0';
118    }
119  *length = rve - digits;
120  return (digits);
121}
122
123/* This function is copied from exponent in vfprintf.c with support for
124   C99 formats removed.  We don't use the original function in order to
125   decouple nano implementation of formatted IO from the Newlib one.  */
126int
127__exponent (char *p0, int exp, int fmtch)
128{
129  register char *p, *t;
130  char expbuf[MAXEXPLEN];
131#define isa 0
132
133  p = p0;
134  *p++ = isa ? 'p' - 'a' + fmtch : fmtch;
135  if (exp < 0)
136    {
137      exp = -exp;
138      *p++ = '-';
139    }
140  else
141    *p++ = '+';
142  t = expbuf + MAXEXPLEN;
143  if (exp > 9)
144    {
145      do
146        {
147          *--t = to_char (exp % 10);
148        }
149      while ((exp /= 10) > 9);
150      *--t = to_char (exp);
151      for (; t < expbuf + MAXEXPLEN; *p++ = *t++);
152    }
153  else
154    {
155      if (!isa)
156        *p++ = '0';
157      *p++ = to_char (exp);
158    }
159  return (p - p0);
160}
161
162/* Decode and print floating point number specified by "eEfgG".  */
163int
164_printf_float (struct _reent *data,
165               struct _prt_data_t *pdata,
166               FILE * fp,
167               int (*pfunc) (struct _reent *, FILE *, const char *,
168                             size_t len), va_list * ap)
169{
170#define _fpvalue (pdata->_double_)
171
172  char *decimal_point = _localeconv_r (data)->decimal_point;
173  size_t decp_len = strlen (decimal_point);
174  /* Temporary negative sign for floats.  */
175  char softsign;
176  /* Integer value of exponent.  */
177  int expt;
178  /* Character count for expstr.  */
179  int expsize = 0;
180  /* Actual number of digits returned by cvt.  */
181  int ndig = 0;
182  char *cp;
183  int n;
184  /* Field size expanded by dprec(not for _printf_float).  */
185  int realsz;
186  char code = pdata->code;
187
188  if (pdata->flags & LONGDBL)
189    {
190      _fpvalue = (double) GET_ARG (N, *ap, _LONG_DOUBLE);
191    }
192  else
193    {
194      _fpvalue = GET_ARG (N, *ap, double);
195    }
196
197  /* Do this before tricky precision changes.
198
199     If the output is infinite or NaN, leading
200     zeros are not permitted.  Otherwise, scanf
201     could not read what printf wrote.  */
202  if (isinf (_fpvalue))
203    {
204      if (_fpvalue < 0)
205        pdata->l_buf[0] = '-';
206      if (code <= 'G')          /* 'A', 'E', 'F', or 'G'.  */
207        cp = "INF";
208      else
209        cp = "inf";
210      pdata->size = 3;
211      pdata->flags &= ~ZEROPAD;
212      goto print_float;
213    }
214  if (isnan (_fpvalue))
215    {
216      if (code <= 'G')          /* 'A', 'E', 'F', or 'G'.  */
217        cp = "NAN";
218      else
219        cp = "nan";
220      pdata->size = 3;
221      pdata->flags &= ~ZEROPAD;
222      goto print_float;
223    }
224
225  if (pdata->prec == -1)
226    {
227      pdata->prec = DEFPREC;
228    }
229  else if ((code == 'g' || code == 'G') && pdata->prec == 0)
230    {
231      pdata->prec = 1;
232    }
233
234  pdata->flags |= FPT;
235
236  cp = __cvt (data, _fpvalue, pdata->prec, pdata->flags, &softsign,
237              &expt, code, &ndig, cp);
238
239  if (code == 'g' || code == 'G')
240    {
241      if (expt <= -4 || expt > pdata->prec)
242        /* 'e' or 'E'.  */
243        code -= 2;
244      else
245        code = 'g';
246    }
247  if (code <= 'e')
248    {
249      /* 'a', 'A', 'e', or 'E' fmt.  */
250      --expt;
251      expsize = __exponent (pdata->expstr, expt, code);
252      pdata->size = expsize + ndig;
253      if (ndig > 1 || pdata->flags & ALT)
254        ++pdata->size;
255    }
256  else
257    {
258      if (code == 'f')
259        {
260          /* 'f' fmt.  */
261          if (expt > 0)
262            {
263              pdata->size = expt;
264              if (pdata->prec || pdata->flags & ALT)
265                pdata->size += pdata->prec + 1;
266            }
267          else
268            /* "0.X".  */
269            pdata->size = (pdata->prec || pdata->flags & ALT)
270              ? pdata->prec + 2 : 1;
271        }
272      else if (expt >= ndig)
273        {
274          /* Fixed g fmt.  */
275          pdata->size = expt;
276          if (pdata->flags & ALT)
277            ++pdata->size;
278        }
279      else
280        pdata->size = ndig + (expt > 0 ? 1 : 2 - expt);
281      pdata->lead = expt;
282    }
283
284  if (softsign)
285    pdata->l_buf[0] = '-';
286print_float:
287  if (_printf_common (data, pdata, &realsz, fp, pfunc) == -1)
288    goto error;
289
290  if ((pdata->flags & FPT) == 0)
291    {
292      PRINT (cp, pdata->size);
293    }
294  else
295    {
296      /* Glue together f_p fragments.  */
297      if (code >= 'f')
298        {
299          /* 'f' or 'g'.  */
300          if (_fpvalue == 0)
301            {
302              /* Kludge for __dtoa irregularity.  */
303              PRINT ("0", 1);
304              if (expt < ndig || pdata->flags & ALT)
305                {
306                  PRINT (decimal_point, decp_len);
307                  PAD (ndig - 1, pdata->zero);
308                }
309            }
310          else if (expt <= 0)
311            {
312              PRINT ("0", 1);
313              if (expt || ndig || pdata->flags & ALT)
314                {
315                  PRINT (decimal_point, decp_len);
316                  PAD (-expt, pdata->zero);
317                  PRINT (cp, ndig);
318                }
319            }
320          else
321            {
322              char *convbuf = cp;
323              PRINTANDPAD (cp, convbuf + ndig, pdata->lead, pdata->zero);
324              cp += pdata->lead;
325              if (expt < ndig || pdata->flags & ALT)
326                PRINT (decimal_point, decp_len);
327              PRINTANDPAD (cp, convbuf + ndig, ndig - expt, pdata->zero);
328            }
329        }
330      else
331        {
332          /* 'a', 'A', 'e', or 'E'.  */
333          if (ndig > 1 || pdata->flags & ALT)
334            {
335              PRINT (cp, 1);
336              cp++;
337              PRINT (decimal_point, decp_len);
338              if (_fpvalue)
339                {
340                  PRINT (cp, ndig - 1);
341                }
342              /* "0.[0..]".  */
343              else
344                /* __dtoa irregularity.  */
345                PAD (ndig - 1, pdata->zero);
346            }
347          else                  /* "XeYYY".  */
348            PRINT (cp, 1);
349          PRINT (pdata->expstr, expsize);
350        }
351    }
352
353  /* Left-adjusting padding (always blank).  */
354  if (pdata->flags & LADJUST)
355    PAD (pdata->width - realsz, pdata->blank);
356
357  return (pdata->width > realsz ? pdata->width : realsz);
358error:
359  return -1;
360
361#undef _fpvalue
362}
363
364#endif
Note: See TracBrowser for help on using the repository browser.