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