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