Hurd: Fix port deallocation on mknod error.
[glibc.git] / stdio-common / printf_fphex.c
blob97ed83be981ff5304908c34927e4bb28ccd16504
1 /* Print floating point number in hexadecimal notation according to ISO C99.
2 Copyright (C) 1997-2002,2004,2006,2011 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>. */
20 #include <ctype.h>
21 #include <ieee754.h>
22 #include <math.h>
23 #include <printf.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <wchar.h>
28 #include <_itoa.h>
29 #include <_itowa.h>
30 #include <locale/localeinfo.h>
32 /* #define NDEBUG 1*/ /* Undefine this for debugging assertions. */
33 #include <assert.h>
35 /* This defines make it possible to use the same code for GNU C library and
36 the GNU I/O library. */
37 #include <libioP.h>
38 #define PUT(f, s, n) _IO_sputn (f, s, n)
39 #define PAD(f, c, n) (wide ? _IO_wpadn (f, c, n) : INTUSE(_IO_padn) (f, c, n))
40 /* We use this file GNU C library and GNU I/O library. So make
41 names equal. */
42 #undef putc
43 #define putc(c, f) (wide \
44 ? (int)_IO_putwc_unlocked (c, f) : _IO_putc_unlocked (c, f))
45 #define size_t _IO_size_t
46 #define FILE _IO_FILE
48 /* Macros for doing the actual output. */
50 #define outchar(ch) \
51 do \
52 { \
53 register const int outc = (ch); \
54 if (putc (outc, fp) == EOF) \
55 return -1; \
56 ++done; \
57 } while (0)
59 #define PRINT(ptr, wptr, len) \
60 do \
61 { \
62 register size_t outlen = (len); \
63 if (wide) \
64 while (outlen-- > 0) \
65 outchar (*wptr++); \
66 else \
67 while (outlen-- > 0) \
68 outchar (*ptr++); \
69 } while (0)
71 #define PADN(ch, len) \
72 do \
73 { \
74 if (PAD (fp, ch, len) != len) \
75 return -1; \
76 done += len; \
77 } \
78 while (0)
80 #ifndef MIN
81 # define MIN(a,b) ((a)<(b)?(a):(b))
82 #endif
85 int
86 __printf_fphex (FILE *fp,
87 const struct printf_info *info,
88 const void *const *args)
90 /* The floating-point value to output. */
91 union
93 union ieee754_double dbl;
94 union ieee854_long_double ldbl;
96 fpnum;
98 /* Locale-dependent representation of decimal point. */
99 const char *decimal;
100 wchar_t decimalwc;
102 /* "NaN" or "Inf" for the special cases. */
103 const char *special = NULL;
104 const wchar_t *wspecial = NULL;
106 /* Buffer for the generated number string for the mantissa. The
107 maximal size for the mantissa is 128 bits. */
108 char numbuf[32];
109 char *numstr;
110 char *numend;
111 wchar_t wnumbuf[32];
112 wchar_t *wnumstr;
113 wchar_t *wnumend;
114 int negative;
116 /* The maximal exponent of two in decimal notation has 5 digits. */
117 char expbuf[5];
118 char *expstr;
119 wchar_t wexpbuf[5];
120 wchar_t *wexpstr;
121 int expnegative;
122 int exponent;
124 /* Non-zero is mantissa is zero. */
125 int zero_mantissa;
127 /* The leading digit before the decimal point. */
128 char leading;
130 /* Precision. */
131 int precision = info->prec;
133 /* Width. */
134 int width = info->width;
136 /* Number of characters written. */
137 int done = 0;
139 /* Nonzero if this is output on a wide character stream. */
140 int wide = info->wide;
143 /* Figure out the decimal point character. */
144 if (info->extra == 0)
146 decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
147 decimalwc = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC);
149 else
151 decimal = _NL_CURRENT (LC_MONETARY, MON_DECIMAL_POINT);
152 decimalwc = _NL_CURRENT_WORD (LC_MONETARY,
153 _NL_MONETARY_DECIMAL_POINT_WC);
155 /* The decimal point character must never be zero. */
156 assert (*decimal != '\0' && decimalwc != L'\0');
159 /* Fetch the argument value. */
160 #ifndef __NO_LONG_DOUBLE_MATH
161 if (info->is_long_double && sizeof (long double) > sizeof (double))
163 fpnum.ldbl.d = *(const long double *) args[0];
165 /* Check for special values: not a number or infinity. */
166 if (__isnanl (fpnum.ldbl.d))
168 negative = fpnum.ldbl.ieee.negative != 0;
169 if (isupper (info->spec))
171 special = "NAN";
172 wspecial = L"NAN";
174 else
176 special = "nan";
177 wspecial = L"nan";
180 else
182 int res = __isinfl (fpnum.ldbl.d);
183 if (res)
185 if (isupper (info->spec))
187 special = "INF";
188 wspecial = L"INF";
190 else
192 special = "inf";
193 wspecial = L"inf";
195 negative = res < 0;
197 else
198 negative = signbit (fpnum.ldbl.d);
201 else
202 #endif /* no long double */
204 fpnum.dbl.d = *(const double *) args[0];
206 /* Check for special values: not a number or infinity. */
207 if (__isnan (fpnum.dbl.d))
209 negative = fpnum.dbl.ieee.negative != 0;
210 if (isupper (info->spec))
212 special = "NAN";
213 wspecial = L"NAN";
215 else
217 special = "nan";
218 wspecial = L"nan";
221 else
223 int res = __isinf (fpnum.dbl.d);
224 if (res)
226 if (isupper (info->spec))
228 special = "INF";
229 wspecial = L"INF";
231 else
233 special = "inf";
234 wspecial = L"inf";
236 negative = res < 0;
238 else
239 negative = signbit (fpnum.dbl.d);
243 if (special)
245 int width = info->width;
247 if (negative || info->showsign || info->space)
248 --width;
249 width -= 3;
251 if (!info->left && width > 0)
252 PADN (' ', width);
254 if (negative)
255 outchar ('-');
256 else if (info->showsign)
257 outchar ('+');
258 else if (info->space)
259 outchar (' ');
261 PRINT (special, wspecial, 3);
263 if (info->left && width > 0)
264 PADN (' ', width);
266 return done;
269 if (info->is_long_double == 0 || sizeof (double) == sizeof (long double))
271 /* We have 52 bits of mantissa plus one implicit digit. Since
272 52 bits are representable without rest using hexadecimal
273 digits we use only the implicit digits for the number before
274 the decimal point. */
275 unsigned long long int num;
277 num = (((unsigned long long int) fpnum.dbl.ieee.mantissa0) << 32
278 | fpnum.dbl.ieee.mantissa1);
280 zero_mantissa = num == 0;
282 if (sizeof (unsigned long int) > 6)
284 wnumstr = _itowa_word (num, wnumbuf + (sizeof wnumbuf) / sizeof (wchar_t), 16,
285 info->spec == 'A');
286 numstr = _itoa_word (num, numbuf + sizeof numbuf, 16,
287 info->spec == 'A');
289 else
291 wnumstr = _itowa (num, wnumbuf + sizeof wnumbuf / sizeof (wchar_t), 16,
292 info->spec == 'A');
293 numstr = _itoa (num, numbuf + sizeof numbuf, 16,
294 info->spec == 'A');
297 /* Fill with zeroes. */
298 while (wnumstr > wnumbuf + (sizeof wnumbuf - 52) / sizeof (wchar_t))
300 *--wnumstr = L'0';
301 *--numstr = '0';
304 leading = fpnum.dbl.ieee.exponent == 0 ? '0' : '1';
306 exponent = fpnum.dbl.ieee.exponent;
308 if (exponent == 0)
310 if (zero_mantissa)
311 expnegative = 0;
312 else
314 /* This is a denormalized number. */
315 expnegative = 1;
316 exponent = IEEE754_DOUBLE_BIAS - 1;
319 else if (exponent >= IEEE754_DOUBLE_BIAS)
321 expnegative = 0;
322 exponent -= IEEE754_DOUBLE_BIAS;
324 else
326 expnegative = 1;
327 exponent = -(exponent - IEEE754_DOUBLE_BIAS);
330 #ifdef PRINT_FPHEX_LONG_DOUBLE
331 else
332 PRINT_FPHEX_LONG_DOUBLE;
333 #endif
335 /* Look for trailing zeroes. */
336 if (! zero_mantissa)
338 wnumend = &wnumbuf[sizeof wnumbuf / sizeof wnumbuf[0]];
339 numend = &numbuf[sizeof numbuf / sizeof numbuf[0]];
340 while (wnumend[-1] == L'0')
342 --wnumend;
343 --numend;
346 if (precision == -1)
347 precision = numend - numstr;
348 else if (precision < numend - numstr
349 && (numstr[precision] > '8'
350 || (('A' < '0' || 'a' < '0')
351 && numstr[precision] < '0')
352 || (numstr[precision] == '8'
353 && (precision + 1 < numend - numstr
354 /* Round to even. */
355 || (precision > 0
356 && ((numstr[precision - 1] & 1)
357 ^ (isdigit (numstr[precision - 1]) == 0)))
358 || (precision == 0
359 && ((leading & 1)
360 ^ (isdigit (leading) == 0)))))))
362 /* Round up. */
363 int cnt = precision;
364 while (--cnt >= 0)
366 char ch = numstr[cnt];
367 /* We assume that the digits and the letters are ordered
368 like in ASCII. This is true for the rest of GNU, too. */
369 if (ch == '9')
371 wnumstr[cnt] = (wchar_t) info->spec;
372 numstr[cnt] = info->spec; /* This is tricky,
373 think about it! */
374 break;
376 else if (tolower (ch) < 'f')
378 ++numstr[cnt];
379 ++wnumstr[cnt];
380 break;
382 else
384 numstr[cnt] = '0';
385 wnumstr[cnt] = L'0';
388 if (cnt < 0)
390 /* The mantissa so far was fff...f Now increment the
391 leading digit. Here it is again possible that we
392 get an overflow. */
393 if (leading == '9')
394 leading = info->spec;
395 else if (tolower (leading) < 'f')
396 ++leading;
397 else
399 leading = '1';
400 if (expnegative)
402 exponent -= 4;
403 if (exponent <= 0)
405 exponent = -exponent;
406 expnegative = 0;
409 else
410 exponent += 4;
415 else
417 if (precision == -1)
418 precision = 0;
419 numend = numstr;
420 wnumend = wnumstr;
423 /* Now we can compute the exponent string. */
424 expstr = _itoa_word (exponent, expbuf + sizeof expbuf, 10, 0);
425 wexpstr = _itowa_word (exponent,
426 wexpbuf + sizeof wexpbuf / sizeof (wchar_t), 10, 0);
428 /* Now we have all information to compute the size. */
429 width -= ((negative || info->showsign || info->space)
430 /* Sign. */
431 + 2 + 1 + 0 + precision + 1 + 1
432 /* 0x h . hhh P ExpoSign. */
433 + ((expbuf + sizeof expbuf) - expstr));
434 /* Exponent. */
436 /* Count the decimal point.
437 A special case when the mantissa or the precision is zero and the `#'
438 is not given. In this case we must not print the decimal point. */
439 if (precision > 0 || info->alt)
440 width -= wide ? 1 : strlen (decimal);
442 if (!info->left && info->pad != '0' && width > 0)
443 PADN (' ', width);
445 if (negative)
446 outchar ('-');
447 else if (info->showsign)
448 outchar ('+');
449 else if (info->space)
450 outchar (' ');
452 outchar ('0');
453 if ('X' - 'A' == 'x' - 'a')
454 outchar (info->spec + ('x' - 'a'));
455 else
456 outchar (info->spec == 'A' ? 'X' : 'x');
458 if (!info->left && info->pad == '0' && width > 0)
459 PADN ('0', width);
461 outchar (leading);
463 if (precision > 0 || info->alt)
465 const wchar_t *wtmp = &decimalwc;
466 PRINT (decimal, wtmp, wide ? 1 : strlen (decimal));
469 if (precision > 0)
471 ssize_t tofill = precision - (numend - numstr);
472 PRINT (numstr, wnumstr, MIN (numend - numstr, precision));
473 if (tofill > 0)
474 PADN ('0', tofill);
477 if ('P' - 'A' == 'p' - 'a')
478 outchar (info->spec + ('p' - 'a'));
479 else
480 outchar (info->spec == 'A' ? 'P' : 'p');
482 outchar (expnegative ? '-' : '+');
484 PRINT (expstr, wexpstr, (expbuf + sizeof expbuf) - expstr);
486 if (info->left && info->pad != '0' && width > 0)
487 PADN (info->pad, width);
489 return done;