linux: Decorate __libc_fatal error buffer
[glibc.git] / stdio-common / printf_fphex.c
blob0c3dfb1a128a4ca5a76eec22d4bd971c6cb0503c
1 /* Print floating point number in hexadecimal notation according to ISO C99.
2 Copyright (C) 1997-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <array_length.h>
20 #include <assert.h>
21 #include <ctype.h>
22 #include <ieee754.h>
23 #include <math.h>
24 #include <printf.h>
25 #include <libioP.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <wchar.h>
30 #include <_itoa.h>
31 #include <_itowa.h>
32 #include <locale/localeinfo.h>
33 #include <stdbool.h>
34 #include <rounding-mode.h>
35 #include <sys/param.h>
36 #include <printf_buffer.h>
37 #include <errno.h>
39 #if __HAVE_DISTINCT_FLOAT128
40 # include "ieee754_float128.h"
41 # include <ldbl-128/printf_fphex_macros.h>
42 # define PRINT_FPHEX_FLOAT128 \
43 PRINT_FPHEX (_Float128, fpnum.flt128, ieee854_float128, \
44 IEEE854_FLOAT128_BIAS)
45 #endif
47 static void
48 __printf_fphex_buffer (struct __printf_buffer *buf,
49 const char *decimal,
50 const struct printf_info *info,
51 const void *const *args)
53 /* The floating-point value to output. */
54 union
56 union ieee754_double dbl;
57 long double ldbl;
58 #if __HAVE_DISTINCT_FLOAT128
59 _Float128 flt128;
60 #endif
62 fpnum;
64 /* This function always uses LC_NUMERIC. */
65 assert (info->extra == 0);
67 /* "NaN" or "Inf" for the special cases. */
68 const char *special = NULL;
70 /* Buffer for the generated number string for the mantissa. The
71 maximal size for the mantissa is 128 bits. */
72 char numbuf[32];
73 char *numstr;
74 char *numend;
75 int negative;
77 /* The maximal exponent of two in decimal notation has 5 digits. */
78 char expbuf[5];
79 char *expstr;
80 int expnegative;
81 int exponent;
83 /* Non-zero is mantissa is zero. */
84 int zero_mantissa;
86 /* The leading digit before the decimal point. */
87 char leading;
89 /* Precision. */
90 int precision = info->prec;
92 /* Width. */
93 int width = info->width;
95 #define PRINTF_FPHEX_FETCH(FLOAT, VAR) \
96 { \
97 (VAR) = *(const FLOAT *) args[0]; \
99 /* Check for special values: not a number or infinity. */ \
100 if (isnan (VAR)) \
102 if (isupper (info->spec)) \
103 special = "NAN"; \
104 else \
105 special = "nan"; \
107 else \
109 if (isinf (VAR)) \
111 if (isupper (info->spec)) \
112 special = "INF"; \
113 else \
114 special = "inf"; \
117 negative = signbit (VAR); \
120 /* Fetch the argument value. */
121 #if __HAVE_DISTINCT_FLOAT128
122 if (info->is_binary128)
123 PRINTF_FPHEX_FETCH (_Float128, fpnum.flt128)
124 else
125 #endif
126 #ifndef __NO_LONG_DOUBLE_MATH
127 if (info->is_long_double && sizeof (long double) > sizeof (double))
128 PRINTF_FPHEX_FETCH (long double, fpnum.ldbl)
129 else
130 #endif
131 PRINTF_FPHEX_FETCH (double, fpnum.dbl.d)
133 #undef PRINTF_FPHEX_FETCH
135 if (special)
137 int width = info->width;
139 if (negative || info->showsign || info->space)
140 --width;
141 width -= 3;
143 if (!info->left)
144 __printf_buffer_pad (buf, ' ', width);
146 if (negative)
147 __printf_buffer_putc (buf, '-');
148 else if (info->showsign)
149 __printf_buffer_putc (buf, '+');
150 else if (info->space)
151 __printf_buffer_putc (buf, ' ');
153 __printf_buffer_puts (buf, special);
155 if (info->left)
156 __printf_buffer_pad (buf, ' ', width);
158 return;
161 #if __HAVE_DISTINCT_FLOAT128
162 if (info->is_binary128)
163 PRINT_FPHEX_FLOAT128;
164 else
165 #endif
166 if (info->is_long_double == 0 || sizeof (double) == sizeof (long double))
168 /* We have 52 bits of mantissa plus one implicit digit. Since
169 52 bits are representable without rest using hexadecimal
170 digits we use only the implicit digits for the number before
171 the decimal point. */
172 unsigned long long int num;
174 num = (((unsigned long long int) fpnum.dbl.ieee.mantissa0) << 32
175 | fpnum.dbl.ieee.mantissa1);
177 zero_mantissa = num == 0;
179 if (sizeof (unsigned long int) > 6)
180 numstr = _itoa_word (num, numbuf + sizeof numbuf, 16,
181 info->spec == 'A');
182 else
183 numstr = _itoa (num, numbuf + sizeof numbuf, 16,
184 info->spec == 'A');
186 /* Fill with zeroes. */
187 while (numstr > numbuf + (sizeof numbuf - 13))
188 *--numstr = '0';
190 leading = fpnum.dbl.ieee.exponent == 0 ? '0' : '1';
192 exponent = fpnum.dbl.ieee.exponent;
194 if (exponent == 0)
196 if (zero_mantissa)
197 expnegative = 0;
198 else
200 /* This is a denormalized number. */
201 expnegative = 1;
202 exponent = IEEE754_DOUBLE_BIAS - 1;
205 else if (exponent >= IEEE754_DOUBLE_BIAS)
207 expnegative = 0;
208 exponent -= IEEE754_DOUBLE_BIAS;
210 else
212 expnegative = 1;
213 exponent = -(exponent - IEEE754_DOUBLE_BIAS);
216 #ifdef PRINT_FPHEX_LONG_DOUBLE
217 else
218 PRINT_FPHEX_LONG_DOUBLE;
219 #endif
221 /* Look for trailing zeroes. */
222 if (! zero_mantissa)
224 numend = array_end (numbuf);
225 while (numend[-1] == '0')
226 --numend;
228 bool do_round_away = false;
230 if (precision != -1 && precision < numend - numstr)
232 char last_digit = precision > 0 ? numstr[precision - 1] : leading;
233 char next_digit = numstr[precision];
234 int last_digit_value = (last_digit >= 'A' && last_digit <= 'F'
235 ? last_digit - 'A' + 10
236 : (last_digit >= 'a' && last_digit <= 'f'
237 ? last_digit - 'a' + 10
238 : last_digit - '0'));
239 int next_digit_value = (next_digit >= 'A' && next_digit <= 'F'
240 ? next_digit - 'A' + 10
241 : (next_digit >= 'a' && next_digit <= 'f'
242 ? next_digit - 'a' + 10
243 : next_digit - '0'));
244 bool more_bits = ((next_digit_value & 7) != 0
245 || precision + 1 < numend - numstr);
246 int rounding_mode = get_rounding_mode ();
247 do_round_away = round_away (negative, last_digit_value & 1,
248 next_digit_value >= 8, more_bits,
249 rounding_mode);
252 if (precision == -1)
253 precision = numend - numstr;
254 else if (do_round_away)
256 /* Round up. */
257 int cnt = precision;
258 while (--cnt >= 0)
260 char ch = numstr[cnt];
261 /* We assume that the digits and the letters are ordered
262 like in ASCII. This is true for the rest of GNU, too. */
263 if (ch == '9')
265 numstr[cnt] = info->spec; /* This is tricky,
266 think about it! */
267 break;
269 else if (tolower (ch) < 'f')
271 ++numstr[cnt];
272 break;
274 else
275 numstr[cnt] = '0';
277 if (cnt < 0)
279 /* The mantissa so far was fff...f Now increment the
280 leading digit. Here it is again possible that we
281 get an overflow. */
282 if (leading == '9')
283 leading = info->spec;
284 else if (tolower (leading) < 'f')
285 ++leading;
286 else
288 leading = '1';
289 if (expnegative)
291 exponent -= 4;
292 if (exponent <= 0)
294 exponent = -exponent;
295 expnegative = 0;
298 else
299 exponent += 4;
304 else
306 if (precision == -1)
307 precision = 0;
308 numend = numstr;
311 /* Now we can compute the exponent string. */
312 expstr = _itoa_word (exponent, expbuf + sizeof expbuf, 10, 0);
314 /* Now we have all information to compute the size. */
315 width -= ((negative || info->showsign || info->space)
316 /* Sign. */
317 + 2 + 1 + 0 + precision + 1 + 1
318 /* 0x h . hhh P ExpoSign. */
319 + ((expbuf + sizeof expbuf) - expstr));
320 /* Exponent. */
322 /* Count the decimal point.
323 A special case when the mantissa or the precision is zero and the `#'
324 is not given. In this case we must not print the decimal point. */
325 if (precision > 0 || info->alt)
326 --width;
328 if (!info->left && info->pad != '0')
329 __printf_buffer_pad (buf, ' ', width);
331 if (negative)
332 __printf_buffer_putc (buf, '-');
333 else if (info->showsign)
334 __printf_buffer_putc (buf, '+');
335 else if (info->space)
336 __printf_buffer_putc (buf, ' ');
338 __printf_buffer_putc (buf, '0');
339 if ('X' - 'A' == 'x' - 'a')
340 __printf_buffer_putc (buf, info->spec + ('x' - 'a'));
341 else
342 __printf_buffer_putc (buf, info->spec == 'A' ? 'X' : 'x');
344 if (!info->left && info->pad == '0')
345 __printf_buffer_pad (buf, '0', width);
347 __printf_buffer_putc (buf, leading);
349 if (precision > 0 || info->alt)
350 __printf_buffer_puts (buf, decimal);
352 if (precision > 0)
354 ssize_t tofill = precision - (numend - numstr);
355 __printf_buffer_write (buf, numstr, MIN (numend - numstr, precision));
356 __printf_buffer_pad (buf, '0', tofill);
359 if ('P' - 'A' == 'p' - 'a')
360 __printf_buffer_putc (buf, info->spec + ('p' - 'a'));
361 else
362 __printf_buffer_putc (buf, info->spec == 'A' ? 'P' : 'p');
364 __printf_buffer_putc (buf, expnegative ? '-' : '+');
366 __printf_buffer_write (buf, expstr, (expbuf + sizeof expbuf) - expstr);
368 if (info->left && info->pad != '0')
369 __printf_buffer_pad (buf, info->pad, width);
372 void
373 __printf_fphex_l_buffer (struct __printf_buffer *buf, locale_t loc,
374 const struct printf_info *info,
375 const void *const *args)
377 __printf_fphex_buffer (buf, _nl_lookup (loc, LC_NUMERIC, DECIMAL_POINT),
378 info, args);
382 /* The wide buffer version is implemented by translating the output of
383 the multibyte version. */
385 struct __printf_buffer_fphex_to_wide
387 struct __printf_buffer base;
388 wchar_t decimalwc;
389 struct __wprintf_buffer *next;
390 char untranslated[PRINTF_BUFFER_SIZE_DIGITS];
393 /* Translate to wide characters, rewriting "." to the actual decimal
394 point. */
395 void
396 __printf_buffer_flush_fphex_to_wide (struct __printf_buffer_fphex_to_wide *buf)
398 /* No need to adjust buf->base.written, only buf->next->written matters. */
399 for (char *p = buf->untranslated; p < buf->base.write_ptr; ++p)
401 /* wchar_t overlaps with char in the ASCII range. */
402 wchar_t ch = *p;
403 if (ch == L'.')
404 ch = buf->decimalwc;
405 __wprintf_buffer_putc (buf->next, ch);
408 if (!__wprintf_buffer_has_failed (buf->next))
409 buf->base.write_ptr = buf->untranslated;
410 else
411 __printf_buffer_mark_failed (&buf->base);
414 void
415 __wprintf_fphex_l_buffer (struct __wprintf_buffer *next, locale_t loc,
416 const struct printf_info *info,
417 const void *const *args)
419 struct __printf_buffer_fphex_to_wide buf;
420 __printf_buffer_init (&buf.base, buf.untranslated, sizeof (buf.untranslated),
421 __printf_buffer_mode_fphex_to_wide);
422 buf.decimalwc = _nl_lookup_word (loc, LC_NUMERIC,
423 _NL_NUMERIC_DECIMAL_POINT_WC);
424 buf.next = next;
425 __printf_fphex_buffer (&buf.base, ".", info, args);
426 if (__printf_buffer_has_failed (&buf.base))
428 __wprintf_buffer_mark_failed (buf.next);
429 return;
431 __printf_buffer_flush_fphex_to_wide (&buf);