2 * Copyright (c) 1990 The Regents of the University of California.
5 * This code is derived from software contributed to Berkeley by
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
47 #include "../stdlib/local.h"
50 #include "nano-vfprintf_local.h"
52 char *__cvt (struct _reent
*data
, _PRINTF_FLOAT_TYPE value
, int ndigits
,
53 int flags
, char *sign
, int *decpt
, int ch
, int *length
,
56 int __exponent (char *p0
, int exp
, int fmtch
);
60 /* Using reentrant DATA, convert finite VALUE into a string of digits
61 with no decimal point, using NDIGITS precision and FLAGS as guides
62 to whether trailing zeros must be included. Set *SIGN to nonzero
63 if VALUE was negative. Set *DECPT to the exponent plus one. Set
64 *LENGTH to the length of the returned string. CH must be one of
65 [aAeEfFgG]; if it is [aA], then the return string lives in BUF,
66 otherwise the return value shares the mprec reentrant storage. */
68 __cvt (struct _reent
*data
, _PRINTF_FLOAT_TYPE value
, int ndigits
, int flags
,
69 char *sign
, int *decpt
, int ch
, int *length
, char *buf
)
72 char *digits
, *bp
, *rve
;
73 union double_union tmp
;
76 /* This will check for "< 0" and "-0.0". */
77 if (word0 (tmp
) & Sign_bit
)
85 if (ch
== 'f' || ch
== 'F')
87 /* Ndigits after the decimal point. */
92 /* To obtain ndigits after the decimal point for the 'e'
93 and 'E' formats, round to ndigits + 1 significant figures. */
94 if (ch
== 'e' || ch
== 'E')
98 /* Ndigits significant digits. */
102 digits
= _DTOA_R (data
, value
, mode
, ndigits
, decpt
, &dsgn
, &rve
);
104 /* Print trailing zeros. */
105 if ((ch
!= 'g' && ch
!= 'G') || flags
& ALT
)
107 bp
= digits
+ ndigits
;
108 if (ch
== 'f' || ch
== 'F')
110 if (*digits
== '0' && value
)
111 *decpt
= -ndigits
+ 1;
114 /* Kludge for __dtoa irregularity. */
120 *length
= rve
- digits
;
124 /* This function is copied from exponent in vfprintf.c with support for
125 C99 formats removed. We don't use the original function in order to
126 decouple nano implementation of formatted IO from the Newlib one. */
128 __exponent (char *p0
, int exp
, int fmtch
)
130 register char *p
, *t
;
131 char expbuf
[MAXEXPLEN
];
135 *p
++ = isa
? 'p' - 'a' + fmtch
: fmtch
;
143 t
= expbuf
+ MAXEXPLEN
;
148 *--t
= to_char (exp
% 10);
150 while ((exp
/= 10) > 9);
151 *--t
= to_char (exp
);
152 for (; t
< expbuf
+ MAXEXPLEN
; *p
++ = *t
++);
158 *p
++ = to_char (exp
);
163 /* Decode and print floating point number specified by "eEfgG". */
165 _printf_float (struct _reent
*data
,
166 struct _prt_data_t
*pdata
,
168 int (*pfunc
) (struct _reent
*, FILE *, const char *,
169 size_t len
), va_list * ap
)
171 #define _fpvalue (pdata->_double_)
173 char *decimal_point
= _localeconv_r (data
)->decimal_point
;
174 size_t decp_len
= strlen (decimal_point
);
175 /* Temporary negative sign for floats. */
177 /* Integer value of exponent. */
179 /* Character count for expstr. */
181 /* Actual number of digits returned by cvt. */
185 /* Field size expanded by dprec(not for _printf_float). */
187 char code
= pdata
->code
;
189 if (pdata
->flags
& LONGDBL
)
191 _fpvalue
= (double) GET_ARG (N
, *ap
, _LONG_DOUBLE
);
195 _fpvalue
= GET_ARG (N
, *ap
, double);
198 /* Do this before tricky precision changes.
200 If the output is infinite or NaN, leading
201 zeros are not permitted. Otherwise, scanf
202 could not read what printf wrote. */
203 if (isinf (_fpvalue
))
206 pdata
->l_buf
[0] = '-';
207 if (code
<= 'G') /* 'A', 'E', 'F', or 'G'. */
212 pdata
->flags
&= ~ZEROPAD
;
215 if (isnan (_fpvalue
))
217 if (signbit (_fpvalue
))
218 pdata
->l_buf
[0] = '-';
219 if (code
<= 'G') /* 'A', 'E', 'F', or 'G'. */
224 pdata
->flags
&= ~ZEROPAD
;
228 if (pdata
->prec
== -1)
230 pdata
->prec
= DEFPREC
;
232 else if ((code
== 'g' || code
== 'G') && pdata
->prec
== 0)
239 cp
= __cvt (data
, _fpvalue
, pdata
->prec
, pdata
->flags
, &softsign
,
240 &expt
, code
, &ndig
, cp
);
242 if (code
== 'g' || code
== 'G')
244 if (expt
<= -4 || expt
> pdata
->prec
)
252 /* 'a', 'A', 'e', or 'E' fmt. */
254 expsize
= __exponent (pdata
->expstr
, expt
, code
);
255 pdata
->size
= expsize
+ ndig
;
256 if (ndig
> 1 || pdata
->flags
& ALT
)
267 if (pdata
->prec
|| pdata
->flags
& ALT
)
268 pdata
->size
+= pdata
->prec
+ 1;
272 pdata
->size
= (pdata
->prec
|| pdata
->flags
& ALT
)
273 ? pdata
->prec
+ 2 : 1;
275 else if (expt
>= ndig
)
279 if (pdata
->flags
& ALT
)
283 pdata
->size
= ndig
+ (expt
> 0 ? 1 : 2 - expt
);
288 pdata
->l_buf
[0] = '-';
290 if (_printf_common (data
, pdata
, &realsz
, fp
, pfunc
) == -1)
293 if ((pdata
->flags
& FPT
) == 0)
295 PRINT (cp
, pdata
->size
);
299 /* Glue together f_p fragments. */
305 /* Kludge for __dtoa irregularity. */
307 if (expt
< ndig
|| pdata
->flags
& ALT
)
309 PRINT (decimal_point
, decp_len
);
310 PAD (ndig
- 1, pdata
->zero
);
316 if (expt
|| ndig
|| pdata
->flags
& ALT
)
318 PRINT (decimal_point
, decp_len
);
319 PAD (-expt
, pdata
->zero
);
326 PRINTANDPAD (cp
, convbuf
+ ndig
, pdata
->lead
, pdata
->zero
);
328 if (expt
< ndig
|| pdata
->flags
& ALT
)
329 PRINT (decimal_point
, decp_len
);
330 PRINTANDPAD (cp
, convbuf
+ ndig
, ndig
- expt
, pdata
->zero
);
335 /* 'a', 'A', 'e', or 'E'. */
336 if (ndig
> 1 || pdata
->flags
& ALT
)
340 PRINT (decimal_point
, decp_len
);
343 PRINT (cp
, ndig
- 1);
347 /* __dtoa irregularity. */
348 PAD (ndig
- 1, pdata
->zero
);
352 PRINT (pdata
->expstr
, expsize
);
356 /* Left-adjusting padding (always blank). */
357 if (pdata
->flags
& LADJUST
)
358 PAD (pdata
->width
- realsz
, pdata
->blank
);
360 return (pdata
->width
> realsz
? pdata
->width
: realsz
);