.
[glibc/history.git] / stdio-common / printf_fphex.c
blob4e30d94c6185bc5c0ca6ef924b565579ba670e62
1 /* Print floating point number in hexadecimal notation according to ISO C99.
2 Copyright (C) 1997-2002,2004,2006 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, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
21 #include <ctype.h>
22 #include <ieee754.h>
23 #include <math.h>
24 #include <printf.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <wchar.h>
29 #include "_itoa.h"
30 #include "_itowa.h"
31 #include <locale/localeinfo.h>
33 /* #define NDEBUG 1*/ /* Undefine this for debugging assertions. */
34 #include <assert.h>
36 /* This defines make it possible to use the same code for GNU C library and
37 the GNU I/O library. */
38 #ifdef USE_IN_LIBIO
39 # include <libioP.h>
40 # define PUT(f, s, n) _IO_sputn (f, s, n)
41 # define PAD(f, c, n) (wide ? _IO_wpadn (f, c, n) : INTUSE(_IO_padn) (f, c, n))
42 /* We use this file GNU C library and GNU I/O library. So make
43 names equal. */
44 # undef putc
45 # define putc(c, f) (wide \
46 ? (int)_IO_putwc_unlocked (c, f) : _IO_putc_unlocked (c, f))
47 # define size_t _IO_size_t
48 # define FILE _IO_FILE
49 #else /* ! USE_IN_LIBIO */
50 # define PUT(f, s, n) fwrite (s, 1, n, f)
51 # define PAD(f, c, n) __printf_pad (f, c, n)
52 ssize_t __printf_pad (FILE *, char pad, int n) __THROW; /* In vfprintf.c. */
53 #endif /* USE_IN_LIBIO */
55 /* Macros for doing the actual output. */
57 #define outchar(ch) \
58 do \
59 { \
60 register const int outc = (ch); \
61 if (putc (outc, fp) == EOF) \
62 return -1; \
63 ++done; \
64 } while (0)
66 #define PRINT(ptr, wptr, len) \
67 do \
68 { \
69 register size_t outlen = (len); \
70 if (wide) \
71 while (outlen-- > 0) \
72 outchar (*wptr++); \
73 else \
74 while (outlen-- > 0) \
75 outchar (*ptr++); \
76 } while (0)
78 #define PADN(ch, len) \
79 do \
80 { \
81 if (PAD (fp, ch, len) != len) \
82 return -1; \
83 done += len; \
84 } \
85 while (0)
87 #ifndef MIN
88 # define MIN(a,b) ((a)<(b)?(a):(b))
89 #endif
92 int
93 __printf_fphex (FILE *fp,
94 const struct printf_info *info,
95 const void *const *args)
97 /* The floating-point value to output. */
98 union
100 union ieee754_double dbl;
101 union ieee854_long_double ldbl;
103 fpnum;
105 /* Locale-dependent representation of decimal point. */
106 const char *decimal;
107 wchar_t decimalwc;
109 /* "NaN" or "Inf" for the special cases. */
110 const char *special = NULL;
111 const wchar_t *wspecial = NULL;
113 /* Buffer for the generated number string for the mantissa. The
114 maximal size for the mantissa is 128 bits. */
115 char numbuf[32];
116 char *numstr;
117 char *numend;
118 wchar_t wnumbuf[32];
119 wchar_t *wnumstr;
120 wchar_t *wnumend;
121 int negative;
123 /* The maximal exponent of two in decimal notation has 5 digits. */
124 char expbuf[5];
125 char *expstr;
126 wchar_t wexpbuf[5];
127 wchar_t *wexpstr;
128 int expnegative;
129 int exponent;
131 /* Non-zero is mantissa is zero. */
132 int zero_mantissa;
134 /* The leading digit before the decimal point. */
135 char leading;
137 /* Precision. */
138 int precision = info->prec;
140 /* Width. */
141 int width = info->width;
143 /* Number of characters written. */
144 int done = 0;
146 /* Nonzero if this is output on a wide character stream. */
147 int wide = info->wide;
150 /* Figure out the decimal point character. */
151 if (info->extra == 0)
153 decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
154 decimalwc = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC);
156 else
158 decimal = _NL_CURRENT (LC_MONETARY, MON_DECIMAL_POINT);
159 decimalwc = _NL_CURRENT_WORD (LC_MONETARY,
160 _NL_MONETARY_DECIMAL_POINT_WC);
162 /* The decimal point character must never be zero. */
163 assert (*decimal != '\0' && decimalwc != L'\0');
166 /* Fetch the argument value. */
167 #ifndef __NO_LONG_DOUBLE_MATH
168 if (info->is_long_double && sizeof (long double) > sizeof (double))
170 fpnum.ldbl.d = *(const long double *) args[0];
172 /* Check for special values: not a number or infinity. */
173 if (__isnanl (fpnum.ldbl.d))
175 if (isupper (info->spec))
177 special = "NAN";
178 wspecial = L"NAN";
180 else
182 special = "nan";
183 wspecial = L"nan";
185 negative = 0;
187 else
189 if (__isinfl (fpnum.ldbl.d))
191 if (isupper (info->spec))
193 special = "INF";
194 wspecial = L"INF";
196 else
198 special = "inf";
199 wspecial = L"inf";
203 negative = signbit (fpnum.ldbl.d);
206 else
207 #endif /* no long double */
209 fpnum.dbl.d = *(const double *) args[0];
211 /* Check for special values: not a number or infinity. */
212 if (__isnan (fpnum.dbl.d))
214 if (isupper (info->spec))
216 special = "NAN";
217 wspecial = L"NAN";
219 else
221 special = "nan";
222 wspecial = L"nan";
224 negative = 0;
226 else
228 if (__isinf (fpnum.dbl.d))
230 if (isupper (info->spec))
232 special = "INF";
233 wspecial = L"INF";
235 else
237 special = "inf";
238 wspecial = L"inf";
242 negative = signbit (fpnum.dbl.d);
246 if (special)
248 int width = info->width;
250 if (negative || info->showsign || info->space)
251 --width;
252 width -= 3;
254 if (!info->left && width > 0)
255 PADN (' ', width);
257 if (negative)
258 outchar ('-');
259 else if (info->showsign)
260 outchar ('+');
261 else if (info->space)
262 outchar (' ');
264 PRINT (special, wspecial, 3);
266 if (info->left && width > 0)
267 PADN (' ', width);
269 return done;
272 if (info->is_long_double == 0 || sizeof (double) == sizeof (long double))
274 /* We have 52 bits of mantissa plus one implicit digit. Since
275 52 bits are representable without rest using hexadecimal
276 digits we use only the implicit digits for the number before
277 the decimal point. */
278 unsigned long long int num;
280 num = (((unsigned long long int) fpnum.dbl.ieee.mantissa0) << 32
281 | fpnum.dbl.ieee.mantissa1);
283 zero_mantissa = num == 0;
285 if (sizeof (unsigned long int) > 6)
287 wnumstr = _itowa_word (num, wnumbuf + (sizeof wnumbuf) / sizeof (wchar_t), 16,
288 info->spec == 'A');
289 numstr = _itoa_word (num, numbuf + sizeof numbuf, 16,
290 info->spec == 'A');
292 else
294 wnumstr = _itowa (num, wnumbuf + sizeof wnumbuf / sizeof (wchar_t), 16,
295 info->spec == 'A');
296 numstr = _itoa (num, numbuf + sizeof numbuf, 16,
297 info->spec == 'A');
300 /* Fill with zeroes. */
301 while (wnumstr > wnumbuf + (sizeof wnumbuf - 52) / sizeof (wchar_t))
303 *--wnumstr = L'0';
304 *--numstr = '0';
307 leading = fpnum.dbl.ieee.exponent == 0 ? '0' : '1';
309 exponent = fpnum.dbl.ieee.exponent;
311 if (exponent == 0)
313 if (zero_mantissa)
314 expnegative = 0;
315 else
317 /* This is a denormalized number. */
318 expnegative = 1;
319 exponent = IEEE754_DOUBLE_BIAS - 1;
322 else if (exponent >= IEEE754_DOUBLE_BIAS)
324 expnegative = 0;
325 exponent -= IEEE754_DOUBLE_BIAS;
327 else
329 expnegative = 1;
330 exponent = -(exponent - IEEE754_DOUBLE_BIAS);
333 #ifdef PRINT_FPHEX_LONG_DOUBLE
334 else
335 PRINT_FPHEX_LONG_DOUBLE;
336 #endif
338 /* Look for trailing zeroes. */
339 if (! zero_mantissa)
341 wnumend = &wnumbuf[sizeof wnumbuf / sizeof wnumbuf[0]];
342 numend = &numbuf[sizeof numbuf / sizeof numbuf[0]];
343 while (wnumend[-1] == L'0')
345 --wnumend;
346 --numend;
349 if (precision == -1)
350 precision = numend - numstr;
351 else if (precision < numend - numstr
352 && (numstr[precision] > '8'
353 || (('A' < '0' || 'a' < '0')
354 && numstr[precision] < '0')
355 || (numstr[precision] == '8'
356 && (precision + 1 < numend - numstr
357 /* Round to even. */
358 || (precision > 0
359 && ((numstr[precision - 1] & 1)
360 ^ (isdigit (numstr[precision - 1]) == 0)))
361 || (precision == 0
362 && ((leading & 1)
363 ^ (isdigit (leading) == 0)))))))
365 /* Round up. */
366 int cnt = precision;
367 while (--cnt >= 0)
369 char ch = numstr[cnt];
370 /* We assume that the digits and the letters are ordered
371 like in ASCII. This is true for the rest of GNU, too. */
372 if (ch == '9')
374 wnumstr[cnt] = (wchar_t) info->spec;
375 numstr[cnt] = info->spec; /* This is tricky,
376 think about it! */
377 break;
379 else if (tolower (ch) < 'f')
381 ++numstr[cnt];
382 ++wnumstr[cnt];
383 break;
385 else
387 numstr[cnt] = '0';
388 wnumstr[cnt] = L'0';
391 if (cnt < 0)
393 /* The mantissa so far was fff...f Now increment the
394 leading digit. Here it is again possible that we
395 get an overflow. */
396 if (leading == '9')
397 leading = info->spec;
398 else if (tolower (leading) < 'f')
399 ++leading;
400 else
402 leading = '1';
403 if (expnegative)
405 exponent -= 4;
406 if (exponent <= 0)
408 exponent = -exponent;
409 expnegative = 0;
412 else
413 exponent += 4;
418 else
420 if (precision == -1)
421 precision = 0;
422 numend = numstr;
423 wnumend = wnumstr;
426 /* Now we can compute the exponent string. */
427 expstr = _itoa_word (exponent, expbuf + sizeof expbuf, 10, 0);
428 wexpstr = _itowa_word (exponent,
429 wexpbuf + sizeof wexpbuf / sizeof (wchar_t), 10, 0);
431 /* Now we have all information to compute the size. */
432 width -= ((negative || info->showsign || info->space)
433 /* Sign. */
434 + 2 + 1 + 0 + precision + 1 + 1
435 /* 0x h . hhh P ExpoSign. */
436 + ((expbuf + sizeof expbuf) - expstr));
437 /* Exponent. */
439 /* Count the decimal point.
440 A special case when the mantissa or the precision is zero and the `#'
441 is not given. In this case we must not print the decimal point. */
442 if (precision > 0 || info->alt)
443 width -= wide ? 1 : strlen (decimal);
445 if (!info->left && info->pad != '0' && width > 0)
446 PADN (' ', width);
448 if (negative)
449 outchar ('-');
450 else if (info->showsign)
451 outchar ('+');
452 else if (info->space)
453 outchar (' ');
455 outchar ('0');
456 if ('X' - 'A' == 'x' - 'a')
457 outchar (info->spec + ('x' - 'a'));
458 else
459 outchar (info->spec == 'A' ? 'X' : 'x');
461 if (!info->left && info->pad == '0' && width > 0)
462 PADN ('0', width);
464 outchar (leading);
466 if (precision > 0 || info->alt)
468 const wchar_t *wtmp = &decimalwc;
469 PRINT (decimal, wtmp, wide ? 1 : strlen (decimal));
472 if (precision > 0)
474 ssize_t tofill = precision - (numend - numstr);
475 PRINT (numstr, wnumstr, MIN (numend - numstr, precision));
476 if (tofill > 0)
477 PADN ('0', tofill);
480 if ('P' - 'A' == 'p' - 'a')
481 outchar (info->spec + ('p' - 'a'));
482 else
483 outchar (info->spec == 'A' ? 'P' : 'p');
485 outchar (expnegative ? '-' : '+');
487 PRINT (expstr, wexpstr, (expbuf + sizeof expbuf) - expstr);
489 if (info->left && info->pad != '0' && width > 0)
490 PADN (info->pad, width);
492 return done;