1 /* Print floating point number in hexadecimal notation according to ISO C99.
2    Copyright (C) 1997-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
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.
9 
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.
14 
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/>.  */
18 
19 #include <array_length.h>
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>
31 #include <stdbool.h>
32 #include <rounding-mode.h>
33 
34 #if __HAVE_DISTINCT_FLOAT128
35 # include "ieee754_float128.h"
36 # include <ldbl-128/printf_fphex_macros.h>
37 # define PRINT_FPHEX_FLOAT128 \
38    PRINT_FPHEX (_Float128, fpnum.flt128, ieee854_float128, \
39 		IEEE854_FLOAT128_BIAS)
40 #endif
41 
42 /* #define NDEBUG 1*/		/* Undefine this for debugging assertions.  */
43 #include <assert.h>
44 
45 #include <libioP.h>
46 #define PUT(f, s, n) _IO_sputn (f, s, n)
47 #define PAD(f, c, n) (wide ? _IO_wpadn (f, c, n) : _IO_padn (f, c, n))
48 #undef putc
49 #define putc(c, f) (wide \
50 		     ? (int)_IO_putwc_unlocked (c, f) : _IO_putc_unlocked (c, f))
51 
52 
53 /* Macros for doing the actual output.  */
54 
55 #define outchar(ch)							      \
56   do									      \
57     {									      \
58       const int outc = (ch);						      \
59       if (putc (outc, fp) == EOF)					      \
60 	return -1;							      \
61       ++done;								      \
62     } while (0)
63 
64 #define PRINT(ptr, wptr, len)						      \
65   do									      \
66     {									      \
67       size_t outlen = (len);						      \
68       if (wide)								      \
69 	while (outlen-- > 0)						      \
70 	  outchar (*wptr++);						      \
71       else								      \
72 	while (outlen-- > 0)						      \
73 	  outchar (*ptr++);						      \
74     } while (0)
75 
76 #define PADN(ch, len)							      \
77   do									      \
78     {									      \
79       if (PAD (fp, ch, len) != len)					      \
80 	return -1;							      \
81       done += len;							      \
82     }									      \
83   while (0)
84 
85 #ifndef MIN
86 # define MIN(a,b) ((a)<(b)?(a):(b))
87 #endif
88 
89 
90 int
__printf_fphex(FILE * fp,const struct printf_info * info,const void * const * args)91 __printf_fphex (FILE *fp,
92 		const struct printf_info *info,
93 		const void *const *args)
94 {
95   /* The floating-point value to output.  */
96   union
97     {
98       union ieee754_double dbl;
99       long double ldbl;
100 #if __HAVE_DISTINCT_FLOAT128
101       _Float128 flt128;
102 #endif
103     }
104   fpnum;
105 
106   /* This function always uses LC_NUMERIC.  */
107   assert (info->extra == 0);
108 
109   /* Locale-dependent representation of decimal point. Hexadecimal
110      formatting always using LC_NUMERIC (disregarding info->extra).  */
111   const char *decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
112   wchar_t decimalwc = _NL_CURRENT_WORD (LC_NUMERIC,
113 					_NL_NUMERIC_DECIMAL_POINT_WC);
114 
115   /* The decimal point character must never be zero.  */
116   assert (*decimal != '\0' && decimalwc != L'\0');
117 
118   /* "NaN" or "Inf" for the special cases.  */
119   const char *special = NULL;
120   const wchar_t *wspecial = NULL;
121 
122   /* Buffer for the generated number string for the mantissa.  The
123      maximal size for the mantissa is 128 bits.  */
124   char numbuf[32];
125   char *numstr;
126   char *numend;
127   wchar_t wnumbuf[32];
128   wchar_t *wnumstr;
129   wchar_t *wnumend;
130   int negative;
131 
132   /* The maximal exponent of two in decimal notation has 5 digits.  */
133   char expbuf[5];
134   char *expstr;
135   wchar_t wexpbuf[5];
136   wchar_t *wexpstr;
137   int expnegative;
138   int exponent;
139 
140   /* Non-zero is mantissa is zero.  */
141   int zero_mantissa;
142 
143   /* The leading digit before the decimal point.  */
144   char leading;
145 
146   /* Precision.  */
147   int precision = info->prec;
148 
149   /* Width.  */
150   int width = info->width;
151 
152   /* Number of characters written.  */
153   int done = 0;
154 
155   /* Nonzero if this is output on a wide character stream.  */
156   int wide = info->wide;
157 
158 #define PRINTF_FPHEX_FETCH(FLOAT, VAR)					\
159   {									\
160     (VAR) = *(const FLOAT *) args[0];					\
161 									\
162     /* Check for special values: not a number or infinity.  */		\
163     if (isnan (VAR))							\
164       {									\
165 	if (isupper (info->spec))					\
166 	  {								\
167 	    special = "NAN";						\
168 	    wspecial = L"NAN";						\
169 	  }								\
170 	else								\
171 	  {								\
172 	    special = "nan";						\
173 	    wspecial = L"nan";						\
174 	  }								\
175       }									\
176     else								\
177       {									\
178 	if (isinf (VAR))						\
179 	  {								\
180 	    if (isupper (info->spec))					\
181 	      {								\
182 		special = "INF";					\
183 		wspecial = L"INF";					\
184 	      }								\
185 	    else							\
186 	      {								\
187 		special = "inf";					\
188 		wspecial = L"inf";					\
189 	      }								\
190 	  }								\
191       }									\
192     negative = signbit (VAR);						\
193   }
194 
195   /* Fetch the argument value.	*/
196 #if __HAVE_DISTINCT_FLOAT128
197   if (info->is_binary128)
198     PRINTF_FPHEX_FETCH (_Float128, fpnum.flt128)
199   else
200 #endif
201 #ifndef __NO_LONG_DOUBLE_MATH
202   if (info->is_long_double && sizeof (long double) > sizeof (double))
203     PRINTF_FPHEX_FETCH (long double, fpnum.ldbl)
204   else
205 #endif
206     PRINTF_FPHEX_FETCH (double, fpnum.dbl.d)
207 
208 #undef PRINTF_FPHEX_FETCH
209 
210   if (special)
211     {
212       int width = info->width;
213 
214       if (negative || info->showsign || info->space)
215 	--width;
216       width -= 3;
217 
218       if (!info->left && width > 0)
219 	PADN (' ', width);
220 
221       if (negative)
222 	outchar ('-');
223       else if (info->showsign)
224 	outchar ('+');
225       else if (info->space)
226 	outchar (' ');
227 
228       PRINT (special, wspecial, 3);
229 
230       if (info->left && width > 0)
231 	PADN (' ', width);
232 
233       return done;
234     }
235 
236 #if __HAVE_DISTINCT_FLOAT128
237   if (info->is_binary128)
238     PRINT_FPHEX_FLOAT128;
239   else
240 #endif
241   if (info->is_long_double == 0 || sizeof (double) == sizeof (long double))
242     {
243       /* We have 52 bits of mantissa plus one implicit digit.  Since
244 	 52 bits are representable without rest using hexadecimal
245 	 digits we use only the implicit digits for the number before
246 	 the decimal point.  */
247       unsigned long long int num;
248 
249       num = (((unsigned long long int) fpnum.dbl.ieee.mantissa0) << 32
250 	     | fpnum.dbl.ieee.mantissa1);
251 
252       zero_mantissa = num == 0;
253 
254       if (sizeof (unsigned long int) > 6)
255 	{
256 	  wnumstr = _itowa_word (num, wnumbuf + (sizeof wnumbuf) / sizeof (wchar_t), 16,
257 				 info->spec == 'A');
258 	  numstr = _itoa_word (num, numbuf + sizeof numbuf, 16,
259 			       info->spec == 'A');
260 	}
261       else
262 	{
263 	  wnumstr = _itowa (num, wnumbuf + sizeof wnumbuf / sizeof (wchar_t), 16,
264 			    info->spec == 'A');
265 	  numstr = _itoa (num, numbuf + sizeof numbuf, 16,
266 			  info->spec == 'A');
267 	}
268 
269       /* Fill with zeroes.  */
270       while (wnumstr > wnumbuf + (sizeof wnumbuf - 52) / sizeof (wchar_t))
271 	{
272 	  *--wnumstr = L'0';
273 	  *--numstr = '0';
274 	}
275 
276       leading = fpnum.dbl.ieee.exponent == 0 ? '0' : '1';
277 
278       exponent = fpnum.dbl.ieee.exponent;
279 
280       if (exponent == 0)
281 	{
282 	  if (zero_mantissa)
283 	    expnegative = 0;
284 	  else
285 	    {
286 	      /* This is a denormalized number.  */
287 	      expnegative = 1;
288 	      exponent = IEEE754_DOUBLE_BIAS - 1;
289 	    }
290 	}
291       else if (exponent >= IEEE754_DOUBLE_BIAS)
292 	{
293 	  expnegative = 0;
294 	  exponent -= IEEE754_DOUBLE_BIAS;
295 	}
296       else
297 	{
298 	  expnegative = 1;
299 	  exponent = -(exponent - IEEE754_DOUBLE_BIAS);
300 	}
301     }
302 #ifdef PRINT_FPHEX_LONG_DOUBLE
303   else
304     PRINT_FPHEX_LONG_DOUBLE;
305 #endif
306 
307   /* Look for trailing zeroes.  */
308   if (! zero_mantissa)
309     {
310       wnumend = array_end (wnumbuf);
311       numend = array_end (numbuf);
312       while (wnumend[-1] == L'0')
313 	{
314 	  --wnumend;
315 	  --numend;
316 	}
317 
318       bool do_round_away = false;
319 
320       if (precision != -1 && precision < numend - numstr)
321 	{
322 	  char last_digit = precision > 0 ? numstr[precision - 1] : leading;
323 	  char next_digit = numstr[precision];
324 	  int last_digit_value = (last_digit >= 'A' && last_digit <= 'F'
325 				  ? last_digit - 'A' + 10
326 				  : (last_digit >= 'a' && last_digit <= 'f'
327 				     ? last_digit - 'a' + 10
328 				     : last_digit - '0'));
329 	  int next_digit_value = (next_digit >= 'A' && next_digit <= 'F'
330 				  ? next_digit - 'A' + 10
331 				  : (next_digit >= 'a' && next_digit <= 'f'
332 				     ? next_digit - 'a' + 10
333 				     : next_digit - '0'));
334 	  bool more_bits = ((next_digit_value & 7) != 0
335 			    || precision + 1 < numend - numstr);
336 	  int rounding_mode = get_rounding_mode ();
337 	  do_round_away = round_away (negative, last_digit_value & 1,
338 				      next_digit_value >= 8, more_bits,
339 				      rounding_mode);
340 	}
341 
342       if (precision == -1)
343 	precision = numend - numstr;
344       else if (do_round_away)
345 	{
346 	  /* Round up.  */
347 	  int cnt = precision;
348 	  while (--cnt >= 0)
349 	    {
350 	      char ch = numstr[cnt];
351 	      /* We assume that the digits and the letters are ordered
352 		 like in ASCII.  This is true for the rest of GNU, too.  */
353 	      if (ch == '9')
354 		{
355 		  wnumstr[cnt] = (wchar_t) info->spec;
356 		  numstr[cnt] = info->spec;	/* This is tricky,
357 						   think about it!  */
358 		  break;
359 		}
360 	      else if (tolower (ch) < 'f')
361 		{
362 		  ++numstr[cnt];
363 		  ++wnumstr[cnt];
364 		  break;
365 		}
366 	      else
367 		{
368 		  numstr[cnt] = '0';
369 		  wnumstr[cnt] = L'0';
370 		}
371 	    }
372 	  if (cnt < 0)
373 	    {
374 	      /* The mantissa so far was fff...f  Now increment the
375 		 leading digit.  Here it is again possible that we
376 		 get an overflow.  */
377 	      if (leading == '9')
378 		leading = info->spec;
379 	      else if (tolower (leading) < 'f')
380 		++leading;
381 	      else
382 		{
383 		  leading = '1';
384 		  if (expnegative)
385 		    {
386 		      exponent -= 4;
387 		      if (exponent <= 0)
388 			{
389 			  exponent = -exponent;
390 			  expnegative = 0;
391 			}
392 		    }
393 		  else
394 		    exponent += 4;
395 		}
396 	    }
397 	}
398     }
399   else
400     {
401       if (precision == -1)
402 	precision = 0;
403       numend = numstr;
404       wnumend = wnumstr;
405     }
406 
407   /* Now we can compute the exponent string.  */
408   expstr = _itoa_word (exponent, expbuf + sizeof expbuf, 10, 0);
409   wexpstr = _itowa_word (exponent,
410 			 wexpbuf + sizeof wexpbuf / sizeof (wchar_t), 10, 0);
411 
412   /* Now we have all information to compute the size.  */
413   width -= ((negative || info->showsign || info->space)
414 	    /* Sign.  */
415 	    + 2    + 1 + 0 + precision + 1 + 1
416 	    /* 0x    h   .   hhh         P   ExpoSign.  */
417 	    + ((expbuf + sizeof expbuf) - expstr));
418 	    /* Exponent.  */
419 
420   /* Count the decimal point.
421      A special case when the mantissa or the precision is zero and the `#'
422      is not given.  In this case we must not print the decimal point.  */
423   if (precision > 0 || info->alt)
424     width -= wide ? 1 : strlen (decimal);
425 
426   if (!info->left && info->pad != '0' && width > 0)
427     PADN (' ', width);
428 
429   if (negative)
430     outchar ('-');
431   else if (info->showsign)
432     outchar ('+');
433   else if (info->space)
434     outchar (' ');
435 
436   outchar ('0');
437   if ('X' - 'A' == 'x' - 'a')
438     outchar (info->spec + ('x' - 'a'));
439   else
440     outchar (info->spec == 'A' ? 'X' : 'x');
441 
442   if (!info->left && info->pad == '0' && width > 0)
443     PADN ('0', width);
444 
445   outchar (leading);
446 
447   if (precision > 0 || info->alt)
448     {
449       const wchar_t *wtmp = &decimalwc;
450       PRINT (decimal, wtmp, wide ? 1 : strlen (decimal));
451     }
452 
453   if (precision > 0)
454     {
455       ssize_t tofill = precision - (numend - numstr);
456       PRINT (numstr, wnumstr, MIN (numend - numstr, precision));
457       if (tofill > 0)
458 	PADN ('0', tofill);
459     }
460 
461   if ('P' - 'A' == 'p' - 'a')
462     outchar (info->spec + ('p' - 'a'));
463   else
464     outchar (info->spec == 'A' ? 'P' : 'p');
465 
466   outchar (expnegative ? '-' : '+');
467 
468   PRINT (expstr, wexpstr, (expbuf + sizeof expbuf) - expstr);
469 
470   if (info->left && info->pad != '0' && width > 0)
471     PADN (info->pad, width);
472 
473   return done;
474 }
475