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 #define _DEFAULT_SOURCE
36 #include <_ansi.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <limits.h>
41 #include <stdint.h>
42 #include <math.h>
43 #include <wchar.h>
44 #include <sys/lock.h>
45 #include <stdarg.h>
46 #include "local.h"
47 #include "../stdlib/local.h"
48 #include "fvwrite.h"
49 #include "vfieeefp.h"
50 #include "nano-vfprintf_local.h"
51
52 char *__cvt (_PRINTF_FLOAT_TYPE value, int ndigits,
53 int flags, char *sign, int *decpt, int ch, int *length,
54 char *buf);
55
56 int __exponent (char *p0, int exp, int fmtch);
57
58 #ifdef FLOATING_POINT
59
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. */
67 char *
__cvt(struct _reent * data,_PRINTF_FLOAT_TYPE value,int ndigits,int flags,char * sign,int * decpt,int ch,int * length,char * buf)68 __cvt (struct _reent *data, _PRINTF_FLOAT_TYPE value, int ndigits, int flags,
69 char *sign, int *decpt, int ch, int *length, char *buf)
70 {
71 int mode, dsgn;
72 char *digits, *bp, *rve;
73 union double_union tmp;
74
75 tmp.d = value;
76 /* This will check for "< 0" and "-0.0". */
77 if (word0 (tmp) & Sign_bit)
78 {
79 value = -value;
80 *sign = '-';
81 }
82 else
83 *sign = '\000';
84
85 if (ch == 'f' || ch == 'F')
86 {
87 /* Ndigits after the decimal point. */
88 mode = 3;
89 }
90 else
91 {
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')
95 {
96 ndigits++;
97 }
98 /* Ndigits significant digits. */
99 mode = 2;
100 }
101
102 digits = _DTOA (value, mode, ndigits, decpt, &dsgn, &rve);
103
104 /* Print trailing zeros. */
105 if ((ch != 'g' && ch != 'G') || flags & ALT)
106 {
107 bp = digits + ndigits;
108 if (ch == 'f' || ch == 'F')
109 {
110 if (*digits == '0' && value)
111 *decpt = -ndigits + 1;
112 bp += *decpt;
113 }
114 /* Kludge for __dtoa irregularity. */
115 if (value == 0)
116 rve = bp;
117 while (rve < bp)
118 *rve++ = '0';
119 }
120 *length = rve - digits;
121 return (digits);
122 }
123
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. */
127 int
__exponent(char * p0,int exp,int fmtch)128 __exponent (char *p0, int exp, int fmtch)
129 {
130 register char *p, *t;
131 char expbuf[MAXEXPLEN];
132 #define isa 0
133
134 p = p0;
135 *p++ = isa ? 'p' - 'a' + fmtch : fmtch;
136 if (exp < 0)
137 {
138 exp = -exp;
139 *p++ = '-';
140 }
141 else
142 *p++ = '+';
143 t = expbuf + MAXEXPLEN;
144 if (exp > 9)
145 {
146 do
147 {
148 *--t = to_char (exp % 10);
149 }
150 while ((exp /= 10) > 9);
151 *--t = to_char (exp);
152 for (; t < expbuf + MAXEXPLEN; *p++ = *t++);
153 }
154 else
155 {
156 if (!isa)
157 *p++ = '0';
158 *p++ = to_char (exp);
159 }
160 return (p - p0);
161 }
162
163 /* Decode and print floating point number specified by "eEfgG". */
164 int
_printf_float(struct _reent * data,struct _prt_data_t * pdata,FILE * fp,int (* pfunc)(struct _reent *,FILE *,const char *,size_t len),va_list * ap)165 _printf_float (struct _reent *data,
166 struct _prt_data_t *pdata,
167 FILE * fp,
168 int (*pfunc) (struct _reent *, FILE *, const char *,
169 size_t len), va_list * ap)
170 {
171 #define _fpvalue (pdata->_double_)
172
173 char *decimal_point = localeconv ()->decimal_point;
174 size_t decp_len = strlen (decimal_point);
175 /* Temporary negative sign for floats. */
176 char softsign;
177 /* Integer value of exponent. */
178 int expt;
179 /* Character count for expstr. */
180 int expsize = 0;
181 /* Actual number of digits returned by cvt. */
182 int ndig = 0;
183 char *cp;
184 int n;
185 /* Field size expanded by dprec(not for _printf_float). */
186 int realsz;
187 char code = pdata->code;
188
189 if (pdata->flags & LONGDBL)
190 {
191 _fpvalue = (double) GET_ARG (N, *ap, _LONG_DOUBLE);
192 }
193 else
194 {
195 _fpvalue = GET_ARG (N, *ap, double);
196 }
197
198 /* Do this before tricky precision changes.
199
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))
204 {
205 if (_fpvalue < 0)
206 pdata->l_buf[0] = '-';
207 if (code <= 'G') /* 'A', 'E', 'F', or 'G'. */
208 cp = "INF";
209 else
210 cp = "inf";
211 pdata->size = 3;
212 pdata->flags &= ~ZEROPAD;
213 goto print_float;
214 }
215 if (isnan (_fpvalue))
216 {
217 if (signbit (_fpvalue))
218 pdata->l_buf[0] = '-';
219 if (code <= 'G') /* 'A', 'E', 'F', or 'G'. */
220 cp = "NAN";
221 else
222 cp = "nan";
223 pdata->size = 3;
224 pdata->flags &= ~ZEROPAD;
225 goto print_float;
226 }
227
228 if (pdata->prec == -1)
229 {
230 pdata->prec = DEFPREC;
231 }
232 else if ((code == 'g' || code == 'G') && pdata->prec == 0)
233 {
234 pdata->prec = 1;
235 }
236
237 pdata->flags |= FPT;
238
239 cp = __cvt (data, _fpvalue, pdata->prec, pdata->flags, &softsign,
240 &expt, code, &ndig, cp);
241
242 if (code == 'g' || code == 'G')
243 {
244 if (expt <= -4 || expt > pdata->prec)
245 /* 'e' or 'E'. */
246 code -= 2;
247 else
248 code = 'g';
249 }
250 if (code <= 'e')
251 {
252 /* 'a', 'A', 'e', or 'E' fmt. */
253 --expt;
254 expsize = __exponent (pdata->expstr, expt, code);
255 pdata->size = expsize + ndig;
256 if (ndig > 1 || pdata->flags & ALT)
257 ++pdata->size;
258 }
259 else
260 {
261 if (code == 'f')
262 {
263 /* 'f' fmt. */
264 if (expt > 0)
265 {
266 pdata->size = expt;
267 if (pdata->prec || pdata->flags & ALT)
268 pdata->size += pdata->prec + 1;
269 }
270 else
271 /* "0.X". */
272 pdata->size = (pdata->prec || pdata->flags & ALT)
273 ? pdata->prec + 2 : 1;
274 }
275 else if (expt >= ndig)
276 {
277 /* Fixed g fmt. */
278 pdata->size = expt;
279 if (pdata->flags & ALT)
280 ++pdata->size;
281 }
282 else
283 pdata->size = ndig + (expt > 0 ? 1 : 2 - expt);
284 pdata->lead = expt;
285 }
286
287 if (softsign)
288 pdata->l_buf[0] = '-';
289 print_float:
290 if (_printf_common (data, pdata, &realsz, fp, pfunc) == -1)
291 goto error;
292
293 if ((pdata->flags & FPT) == 0)
294 {
295 PRINT (cp, pdata->size);
296 }
297 else
298 {
299 /* Glue together f_p fragments. */
300 if (code >= 'f')
301 {
302 /* 'f' or 'g'. */
303 if (_fpvalue == 0)
304 {
305 /* Kludge for __dtoa irregularity. */
306 PRINT ("0", 1);
307 if (expt < ndig || pdata->flags & ALT)
308 {
309 PRINT (decimal_point, decp_len);
310 PAD (ndig - 1, pdata->zero);
311 }
312 }
313 else if (expt <= 0)
314 {
315 PRINT ("0", 1);
316 if (expt || ndig || pdata->flags & ALT)
317 {
318 PRINT (decimal_point, decp_len);
319 PAD (-expt, pdata->zero);
320 PRINT (cp, ndig);
321 }
322 }
323 else
324 {
325 char *convbuf = cp;
326 PRINTANDPAD (cp, convbuf + ndig, pdata->lead, pdata->zero);
327 cp += pdata->lead;
328 if (expt < ndig || pdata->flags & ALT)
329 PRINT (decimal_point, decp_len);
330 PRINTANDPAD (cp, convbuf + ndig, ndig - expt, pdata->zero);
331 }
332 }
333 else
334 {
335 /* 'a', 'A', 'e', or 'E'. */
336 if (ndig > 1 || pdata->flags & ALT)
337 {
338 PRINT (cp, 1);
339 cp++;
340 PRINT (decimal_point, decp_len);
341 if (_fpvalue)
342 {
343 PRINT (cp, ndig - 1);
344 }
345 /* "0.[0..]". */
346 else
347 /* __dtoa irregularity. */
348 PAD (ndig - 1, pdata->zero);
349 }
350 else /* "XeYYY". */
351 PRINT (cp, 1);
352 PRINT (pdata->expstr, expsize);
353 }
354 }
355
356 /* Left-adjusting padding (always blank). */
357 if (pdata->flags & LADJUST)
358 PAD (pdata->width - realsz, pdata->blank);
359
360 return (pdata->width > realsz ? pdata->width : realsz);
361 error:
362 return -1;
363
364 #undef _fpvalue
365 }
366
367 #endif
368