| /* Print floating point number in hexadecimal notation according to ISO C99. | 
 |    Copyright (C) 1997-2016 Free Software Foundation, Inc. | 
 |    This file is part of the GNU C Library. | 
 |    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. | 
 |  | 
 |    The GNU C Library is free software; you can redistribute it and/or | 
 |    modify it under the terms of the GNU Lesser General Public | 
 |    License as published by the Free Software Foundation; either | 
 |    version 2.1 of the License, or (at your option) any later version. | 
 |  | 
 |    The GNU C Library is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |    Lesser General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU Lesser General Public | 
 |    License along with the GNU C Library; if not, see | 
 |    <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include <ctype.h> | 
 | #include <ieee754.h> | 
 | #include <math.h> | 
 | #include <printf.h> | 
 | #include <stdlib.h> | 
 | #include <stdio.h> | 
 | #include <string.h> | 
 | #include <wchar.h> | 
 | #include <_itoa.h> | 
 | #include <_itowa.h> | 
 | #include <locale/localeinfo.h> | 
 | #include <stdbool.h> | 
 | #include <rounding-mode.h> | 
 |  | 
 | /* #define NDEBUG 1*/		/* Undefine this for debugging assertions.  */ | 
 | #include <assert.h> | 
 |  | 
 | /* This defines make it possible to use the same code for GNU C library and | 
 |    the GNU I/O library.	 */ | 
 | #include <libioP.h> | 
 | #define PUT(f, s, n) _IO_sputn (f, s, n) | 
 | #define PAD(f, c, n) (wide ? _IO_wpadn (f, c, n) : _IO_padn (f, c, n)) | 
 | /* We use this file GNU C library and GNU I/O library.	So make | 
 |    names equal.	 */ | 
 | #undef putc | 
 | #define putc(c, f) (wide \ | 
 | 		     ? (int)_IO_putwc_unlocked (c, f) : _IO_putc_unlocked (c, f)) | 
 | #define size_t     _IO_size_t | 
 | #define FILE	     _IO_FILE | 
 |  | 
 | /* Macros for doing the actual output.  */ | 
 |  | 
 | #define outchar(ch)							      \ | 
 |   do									      \ | 
 |     {									      \ | 
 |       const int outc = (ch);						      \ | 
 |       if (putc (outc, fp) == EOF)					      \ | 
 | 	return -1;							      \ | 
 |       ++done;								      \ | 
 |     } while (0) | 
 |  | 
 | #define PRINT(ptr, wptr, len)						      \ | 
 |   do									      \ | 
 |     {									      \ | 
 |       size_t outlen = (len);						      \ | 
 |       if (wide)								      \ | 
 | 	while (outlen-- > 0)						      \ | 
 | 	  outchar (*wptr++);						      \ | 
 |       else								      \ | 
 | 	while (outlen-- > 0)						      \ | 
 | 	  outchar (*ptr++);						      \ | 
 |     } while (0) | 
 |  | 
 | #define PADN(ch, len)							      \ | 
 |   do									      \ | 
 |     {									      \ | 
 |       if (PAD (fp, ch, len) != len)					      \ | 
 | 	return -1;							      \ | 
 |       done += len;							      \ | 
 |     }									      \ | 
 |   while (0) | 
 |  | 
 | #ifndef MIN | 
 | # define MIN(a,b) ((a)<(b)?(a):(b)) | 
 | #endif | 
 |  | 
 |  | 
 | int | 
 | __printf_fphex (FILE *fp, | 
 | 		const struct printf_info *info, | 
 | 		const void *const *args) | 
 | { | 
 |   /* The floating-point value to output.  */ | 
 |   union | 
 |     { | 
 |       union ieee754_double dbl; | 
 |       long double ldbl; | 
 |     } | 
 |   fpnum; | 
 |  | 
 |   /* Locale-dependent representation of decimal point.	*/ | 
 |   const char *decimal; | 
 |   wchar_t decimalwc; | 
 |  | 
 |   /* "NaN" or "Inf" for the special cases.  */ | 
 |   const char *special = NULL; | 
 |   const wchar_t *wspecial = NULL; | 
 |  | 
 |   /* Buffer for the generated number string for the mantissa.  The | 
 |      maximal size for the mantissa is 128 bits.  */ | 
 |   char numbuf[32]; | 
 |   char *numstr; | 
 |   char *numend; | 
 |   wchar_t wnumbuf[32]; | 
 |   wchar_t *wnumstr; | 
 |   wchar_t *wnumend; | 
 |   int negative; | 
 |  | 
 |   /* The maximal exponent of two in decimal notation has 5 digits.  */ | 
 |   char expbuf[5]; | 
 |   char *expstr; | 
 |   wchar_t wexpbuf[5]; | 
 |   wchar_t *wexpstr; | 
 |   int expnegative; | 
 |   int exponent; | 
 |  | 
 |   /* Non-zero is mantissa is zero.  */ | 
 |   int zero_mantissa; | 
 |  | 
 |   /* The leading digit before the decimal point.  */ | 
 |   char leading; | 
 |  | 
 |   /* Precision.  */ | 
 |   int precision = info->prec; | 
 |  | 
 |   /* Width.  */ | 
 |   int width = info->width; | 
 |  | 
 |   /* Number of characters written.  */ | 
 |   int done = 0; | 
 |  | 
 |   /* Nonzero if this is output on a wide character stream.  */ | 
 |   int wide = info->wide; | 
 |  | 
 |  | 
 |   /* Figure out the decimal point character.  */ | 
 |   if (info->extra == 0) | 
 |     { | 
 |       decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT); | 
 |       decimalwc = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC); | 
 |     } | 
 |   else | 
 |     { | 
 |       decimal = _NL_CURRENT (LC_MONETARY, MON_DECIMAL_POINT); | 
 |       decimalwc = _NL_CURRENT_WORD (LC_MONETARY, | 
 | 				    _NL_MONETARY_DECIMAL_POINT_WC); | 
 |     } | 
 |   /* The decimal point character must never be zero.  */ | 
 |   assert (*decimal != '\0' && decimalwc != L'\0'); | 
 |  | 
 |  | 
 |   /* Fetch the argument value.	*/ | 
 | #ifndef __NO_LONG_DOUBLE_MATH | 
 |   if (info->is_long_double && sizeof (long double) > sizeof (double)) | 
 |     { | 
 |       fpnum.ldbl = *(const long double *) args[0]; | 
 |  | 
 |       /* Check for special values: not a number or infinity.  */ | 
 |       if (isnan (fpnum.ldbl)) | 
 | 	{ | 
 | 	  if (isupper (info->spec)) | 
 | 	    { | 
 | 	      special = "NAN"; | 
 | 	      wspecial = L"NAN"; | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      special = "nan"; | 
 | 	      wspecial = L"nan"; | 
 | 	    } | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  if (isinf (fpnum.ldbl)) | 
 | 	    { | 
 | 	      if (isupper (info->spec)) | 
 | 		{ | 
 | 		  special = "INF"; | 
 | 		  wspecial = L"INF"; | 
 | 		} | 
 | 	      else | 
 | 		{ | 
 | 		  special = "inf"; | 
 | 		  wspecial = L"inf"; | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |       negative = signbit (fpnum.ldbl); | 
 |     } | 
 |   else | 
 | #endif	/* no long double */ | 
 |     { | 
 |       fpnum.dbl.d = *(const double *) args[0]; | 
 |  | 
 |       /* Check for special values: not a number or infinity.  */ | 
 |       if (isnan (fpnum.dbl.d)) | 
 | 	{ | 
 | 	  if (isupper (info->spec)) | 
 | 	    { | 
 | 	      special = "NAN"; | 
 | 	      wspecial = L"NAN"; | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      special = "nan"; | 
 | 	      wspecial = L"nan"; | 
 | 	    } | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  if (isinf (fpnum.dbl.d)) | 
 | 	    { | 
 | 	      if (isupper (info->spec)) | 
 | 		{ | 
 | 		  special = "INF"; | 
 | 		  wspecial = L"INF"; | 
 | 		} | 
 | 	      else | 
 | 		{ | 
 | 		  special = "inf"; | 
 | 		  wspecial = L"inf"; | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |       negative = signbit (fpnum.dbl.d); | 
 |     } | 
 |  | 
 |   if (special) | 
 |     { | 
 |       int width = info->width; | 
 |  | 
 |       if (negative || info->showsign || info->space) | 
 | 	--width; | 
 |       width -= 3; | 
 |  | 
 |       if (!info->left && width > 0) | 
 | 	PADN (' ', width); | 
 |  | 
 |       if (negative) | 
 | 	outchar ('-'); | 
 |       else if (info->showsign) | 
 | 	outchar ('+'); | 
 |       else if (info->space) | 
 | 	outchar (' '); | 
 |  | 
 |       PRINT (special, wspecial, 3); | 
 |  | 
 |       if (info->left && width > 0) | 
 | 	PADN (' ', width); | 
 |  | 
 |       return done; | 
 |     } | 
 |  | 
 |   if (info->is_long_double == 0 || sizeof (double) == sizeof (long double)) | 
 |     { | 
 |       /* We have 52 bits of mantissa plus one implicit digit.  Since | 
 | 	 52 bits are representable without rest using hexadecimal | 
 | 	 digits we use only the implicit digits for the number before | 
 | 	 the decimal point.  */ | 
 |       unsigned long long int num; | 
 |  | 
 |       num = (((unsigned long long int) fpnum.dbl.ieee.mantissa0) << 32 | 
 | 	     | fpnum.dbl.ieee.mantissa1); | 
 |  | 
 |       zero_mantissa = num == 0; | 
 |  | 
 |       if (sizeof (unsigned long int) > 6) | 
 | 	{ | 
 | 	  wnumstr = _itowa_word (num, wnumbuf + (sizeof wnumbuf) / sizeof (wchar_t), 16, | 
 | 				 info->spec == 'A'); | 
 | 	  numstr = _itoa_word (num, numbuf + sizeof numbuf, 16, | 
 | 			       info->spec == 'A'); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  wnumstr = _itowa (num, wnumbuf + sizeof wnumbuf / sizeof (wchar_t), 16, | 
 | 			    info->spec == 'A'); | 
 | 	  numstr = _itoa (num, numbuf + sizeof numbuf, 16, | 
 | 			  info->spec == 'A'); | 
 | 	} | 
 |  | 
 |       /* Fill with zeroes.  */ | 
 |       while (wnumstr > wnumbuf + (sizeof wnumbuf - 52) / sizeof (wchar_t)) | 
 | 	{ | 
 | 	  *--wnumstr = L'0'; | 
 | 	  *--numstr = '0'; | 
 | 	} | 
 |  | 
 |       leading = fpnum.dbl.ieee.exponent == 0 ? '0' : '1'; | 
 |  | 
 |       exponent = fpnum.dbl.ieee.exponent; | 
 |  | 
 |       if (exponent == 0) | 
 | 	{ | 
 | 	  if (zero_mantissa) | 
 | 	    expnegative = 0; | 
 | 	  else | 
 | 	    { | 
 | 	      /* This is a denormalized number.  */ | 
 | 	      expnegative = 1; | 
 | 	      exponent = IEEE754_DOUBLE_BIAS - 1; | 
 | 	    } | 
 | 	} | 
 |       else if (exponent >= IEEE754_DOUBLE_BIAS) | 
 | 	{ | 
 | 	  expnegative = 0; | 
 | 	  exponent -= IEEE754_DOUBLE_BIAS; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  expnegative = 1; | 
 | 	  exponent = -(exponent - IEEE754_DOUBLE_BIAS); | 
 | 	} | 
 |     } | 
 | #ifdef PRINT_FPHEX_LONG_DOUBLE | 
 |   else | 
 |     PRINT_FPHEX_LONG_DOUBLE; | 
 | #endif | 
 |  | 
 |   /* Look for trailing zeroes.  */ | 
 |   if (! zero_mantissa) | 
 |     { | 
 |       wnumend = &wnumbuf[sizeof wnumbuf / sizeof wnumbuf[0]]; | 
 |       numend = &numbuf[sizeof numbuf / sizeof numbuf[0]]; | 
 |       while (wnumend[-1] == L'0') | 
 | 	{ | 
 | 	  --wnumend; | 
 | 	  --numend; | 
 | 	} | 
 |  | 
 |       bool do_round_away = false; | 
 |  | 
 |       if (precision != -1 && precision < numend - numstr) | 
 | 	{ | 
 | 	  char last_digit = precision > 0 ? numstr[precision - 1] : leading; | 
 | 	  char next_digit = numstr[precision]; | 
 | 	  int last_digit_value = (last_digit >= 'A' && last_digit <= 'F' | 
 | 				  ? last_digit - 'A' + 10 | 
 | 				  : (last_digit >= 'a' && last_digit <= 'f' | 
 | 				     ? last_digit - 'a' + 10 | 
 | 				     : last_digit - '0')); | 
 | 	  int next_digit_value = (next_digit >= 'A' && next_digit <= 'F' | 
 | 				  ? next_digit - 'A' + 10 | 
 | 				  : (next_digit >= 'a' && next_digit <= 'f' | 
 | 				     ? next_digit - 'a' + 10 | 
 | 				     : next_digit - '0')); | 
 | 	  bool more_bits = ((next_digit_value & 7) != 0 | 
 | 			    || precision + 1 < numend - numstr); | 
 | 	  int rounding_mode = get_rounding_mode (); | 
 | 	  do_round_away = round_away (negative, last_digit_value & 1, | 
 | 				      next_digit_value >= 8, more_bits, | 
 | 				      rounding_mode); | 
 | 	} | 
 |  | 
 |       if (precision == -1) | 
 | 	precision = numend - numstr; | 
 |       else if (do_round_away) | 
 | 	{ | 
 | 	  /* Round up.  */ | 
 | 	  int cnt = precision; | 
 | 	  while (--cnt >= 0) | 
 | 	    { | 
 | 	      char ch = numstr[cnt]; | 
 | 	      /* We assume that the digits and the letters are ordered | 
 | 		 like in ASCII.  This is true for the rest of GNU, too.  */ | 
 | 	      if (ch == '9') | 
 | 		{ | 
 | 		  wnumstr[cnt] = (wchar_t) info->spec; | 
 | 		  numstr[cnt] = info->spec;	/* This is tricky, | 
 | 						   think about it!  */ | 
 | 		  break; | 
 | 		} | 
 | 	      else if (tolower (ch) < 'f') | 
 | 		{ | 
 | 		  ++numstr[cnt]; | 
 | 		  ++wnumstr[cnt]; | 
 | 		  break; | 
 | 		} | 
 | 	      else | 
 | 		{ | 
 | 		  numstr[cnt] = '0'; | 
 | 		  wnumstr[cnt] = L'0'; | 
 | 		} | 
 | 	    } | 
 | 	  if (cnt < 0) | 
 | 	    { | 
 | 	      /* The mantissa so far was fff...f  Now increment the | 
 | 		 leading digit.  Here it is again possible that we | 
 | 		 get an overflow.  */ | 
 | 	      if (leading == '9') | 
 | 		leading = info->spec; | 
 | 	      else if (tolower (leading) < 'f') | 
 | 		++leading; | 
 | 	      else | 
 | 		{ | 
 | 		  leading = '1'; | 
 | 		  if (expnegative) | 
 | 		    { | 
 | 		      exponent -= 4; | 
 | 		      if (exponent <= 0) | 
 | 			{ | 
 | 			  exponent = -exponent; | 
 | 			  expnegative = 0; | 
 | 			} | 
 | 		    } | 
 | 		  else | 
 | 		    exponent += 4; | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |     } | 
 |   else | 
 |     { | 
 |       if (precision == -1) | 
 | 	precision = 0; | 
 |       numend = numstr; | 
 |       wnumend = wnumstr; | 
 |     } | 
 |  | 
 |   /* Now we can compute the exponent string.  */ | 
 |   expstr = _itoa_word (exponent, expbuf + sizeof expbuf, 10, 0); | 
 |   wexpstr = _itowa_word (exponent, | 
 | 			 wexpbuf + sizeof wexpbuf / sizeof (wchar_t), 10, 0); | 
 |  | 
 |   /* Now we have all information to compute the size.  */ | 
 |   width -= ((negative || info->showsign || info->space) | 
 | 	    /* Sign.  */ | 
 | 	    + 2    + 1 + 0 + precision + 1 + 1 | 
 | 	    /* 0x    h   .   hhh         P   ExpoSign.  */ | 
 | 	    + ((expbuf + sizeof expbuf) - expstr)); | 
 | 	    /* Exponent.  */ | 
 |  | 
 |   /* Count the decimal point. | 
 |      A special case when the mantissa or the precision is zero and the `#' | 
 |      is not given.  In this case we must not print the decimal point.  */ | 
 |   if (precision > 0 || info->alt) | 
 |     width -= wide ? 1 : strlen (decimal); | 
 |  | 
 |   if (!info->left && info->pad != '0' && width > 0) | 
 |     PADN (' ', width); | 
 |  | 
 |   if (negative) | 
 |     outchar ('-'); | 
 |   else if (info->showsign) | 
 |     outchar ('+'); | 
 |   else if (info->space) | 
 |     outchar (' '); | 
 |  | 
 |   outchar ('0'); | 
 |   if ('X' - 'A' == 'x' - 'a') | 
 |     outchar (info->spec + ('x' - 'a')); | 
 |   else | 
 |     outchar (info->spec == 'A' ? 'X' : 'x'); | 
 |  | 
 |   if (!info->left && info->pad == '0' && width > 0) | 
 |     PADN ('0', width); | 
 |  | 
 |   outchar (leading); | 
 |  | 
 |   if (precision > 0 || info->alt) | 
 |     { | 
 |       const wchar_t *wtmp = &decimalwc; | 
 |       PRINT (decimal, wtmp, wide ? 1 : strlen (decimal)); | 
 |     } | 
 |  | 
 |   if (precision > 0) | 
 |     { | 
 |       ssize_t tofill = precision - (numend - numstr); | 
 |       PRINT (numstr, wnumstr, MIN (numend - numstr, precision)); | 
 |       if (tofill > 0) | 
 | 	PADN ('0', tofill); | 
 |     } | 
 |  | 
 |   if ('P' - 'A' == 'p' - 'a') | 
 |     outchar (info->spec + ('p' - 'a')); | 
 |   else | 
 |     outchar (info->spec == 'A' ? 'P' : 'p'); | 
 |  | 
 |   outchar (expnegative ? '-' : '+'); | 
 |  | 
 |   PRINT (expstr, wexpstr, (expbuf + sizeof expbuf) - expstr); | 
 |  | 
 |   if (info->left && info->pad != '0' && width > 0) | 
 |     PADN (info->pad, width); | 
 |  | 
 |   return done; | 
 | } |