1 /* Print floating point number in hexadecimal notation according to ISO C99.
2    Copyright (C) 1997-2012 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
5 
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.
10 
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.
15 
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, see
18    <http://www.gnu.org/licenses/>.  */
19 
20 #include <config.h>
21 #include <math.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdbool.h>
26 #define NDEBUG
27 #include <assert.h>
28 #include "quadmath-rounding-mode.h"
29 #include "quadmath-printf.h"
30 #include "_itoa.h"
31 #include "_itowa.h"
32 
33 
34 /* Macros for doing the actual output.  */
35 
36 #define outchar(ch)							      \
37   do									      \
38     {									      \
39       register const int outc = (ch);					      \
40       if (PUTC (outc, fp) == EOF)					      \
41 	return -1;							      \
42       ++done;								      \
43     } while (0)
44 
45 #define PRINT(ptr, wptr, len)						      \
46   do									      \
47     {									      \
48       register size_t outlen = (len);					      \
49       if (wide)								      \
50 	while (outlen-- > 0)						      \
51 	  outchar (*wptr++);						      \
52       else								      \
53 	while (outlen-- > 0)						      \
54 	  outchar (*ptr++);						      \
55     } while (0)
56 
57 #define PADN(ch, len)							      \
58   do									      \
59     {									      \
60       if (PAD (fp, ch, len) != len)					      \
61 	return -1;							      \
62       done += len;							      \
63     }									      \
64   while (0)
65 
66 
67 
68 int
__quadmath_printf_fphex(struct __quadmath_printf_file * fp,const struct printf_info * info,const void * const * args)69 __quadmath_printf_fphex (struct __quadmath_printf_file *fp,
70 			 const struct printf_info *info,
71 			 const void *const *args)
72 {
73   /* The floating-point value to output.  */
74   ieee854_float128 fpnum;
75 
76   /* Locale-dependent representation of decimal point.	*/
77   const char *decimal;
78   wchar_t decimalwc;
79 
80   /* "NaN" or "Inf" for the special cases.  */
81   const char *special = NULL;
82   const wchar_t *wspecial = NULL;
83 
84   /* Buffer for the generated number string for the mantissa.  The
85      maximal size for the mantissa is 128 bits.  */
86   char numbuf[32];
87   char *numstr;
88   char *numend;
89   wchar_t wnumbuf[32];
90   wchar_t *wnumstr;
91   wchar_t *wnumend;
92   int negative;
93 
94   /* The maximal exponent of two in decimal notation has 5 digits.  */
95   char expbuf[5];
96   char *expstr;
97   wchar_t wexpbuf[5];
98   wchar_t *wexpstr;
99   int expnegative;
100   int exponent;
101 
102   /* Non-zero is mantissa is zero.  */
103   int zero_mantissa;
104 
105   /* The leading digit before the decimal point.  */
106   char leading;
107 
108   /* Precision.  */
109   int precision = info->prec;
110 
111   /* Width.  */
112   int width = info->width;
113 
114   /* Number of characters written.  */
115   int done = 0;
116 
117   /* Nonzero if this is output on a wide character stream.  */
118   int wide = info->wide;
119 
120   bool do_round_away;
121 
122   /* Figure out the decimal point character.  */
123 #ifdef USE_NL_LANGINFO
124   if (info->extra == 0)
125     decimal = nl_langinfo (DECIMAL_POINT);
126   else
127     {
128       decimal = nl_langinfo (MON_DECIMAL_POINT);
129       if (*decimal == '\0')
130 	decimal = nl_langinfo (DECIMAL_POINT);
131     }
132   /* The decimal point character must never be zero.  */
133   assert (*decimal != '\0');
134 #elif defined USE_LOCALECONV
135   const struct lconv *lc = localeconv ();
136   if (info->extra == 0)
137     decimal = lc->decimal_point;
138   else
139     {
140       decimal = lc->mon_decimal_point;
141       if (decimal == NULL || *decimal == '\0')
142 	decimal = lc->decimal_point;
143     }
144   if (decimal == NULL || *decimal == '\0')
145     decimal = ".";
146 #else
147   decimal = ".";
148 #endif
149 #ifdef USE_NL_LANGINFO_WC
150   if (info->extra == 0)
151     decimalwc = nl_langinfo_wc (_NL_NUMERIC_DECIMAL_POINT_WC);
152   else
153     {
154       decimalwc = nl_langinfo_wc (_NL_MONETARY_DECIMAL_POINT_WC);
155       if (decimalwc == L_('\0'))
156 	decimalwc = nl_langinfo_wc (_NL_NUMERIC_DECIMAL_POINT_WC);
157     }
158   /* The decimal point character must never be zero.  */
159   assert (decimalwc != L_('\0'));
160 #else
161   decimalwc = L_('.');
162 #endif
163 
164   /* Fetch the argument value.	*/
165     {
166       fpnum.value = **(const __float128 **) args[0];
167 
168       /* Check for special values: not a number or infinity.  */
169       if (isnanq (fpnum.value))
170 	{
171 	  negative = fpnum.ieee.negative != 0;
172 	  if (isupper (info->spec))
173 	    {
174 	      special = "NAN";
175 	      wspecial = L_("NAN");
176 	    }
177 	  else
178 	    {
179 	      special = "nan";
180 	      wspecial = L_("nan");
181 	    }
182 	}
183       else
184 	{
185 	  if (isinfq (fpnum.value))
186 	    {
187 	      if (isupper (info->spec))
188 		{
189 		  special = "INF";
190 		  wspecial = L_("INF");
191 		}
192 	      else
193 		{
194 		  special = "inf";
195 		  wspecial = L_("inf");
196 		}
197 	    }
198 
199 	  negative = signbitq (fpnum.value);
200 	}
201     }
202 
203   if (special)
204     {
205       int width = info->width;
206 
207       if (negative || info->showsign || info->space)
208 	--width;
209       width -= 3;
210 
211       if (!info->left && width > 0)
212 	PADN (' ', width);
213 
214       if (negative)
215 	outchar ('-');
216       else if (info->showsign)
217 	outchar ('+');
218       else if (info->space)
219 	outchar (' ');
220 
221       PRINT (special, wspecial, 3);
222 
223       if (info->left && width > 0)
224 	PADN (' ', width);
225 
226       return done;
227     }
228 
229     {
230       /* We have 112 bits of mantissa plus one implicit digit.  Since
231 	 112 bits are representable without rest using hexadecimal
232 	 digits we use only the implicit digits for the number before
233 	 the decimal point.  */
234       uint64_t num0, num1;
235 
236       assert (sizeof (long double) == 16);
237 
238       num0 = (((unsigned long long int) fpnum.ieee.mantissa0) << 32
239 	      | fpnum.ieee.mantissa1);
240       num1 = (((unsigned long long int) fpnum.ieee.mantissa2) << 32
241 	      | fpnum.ieee.mantissa3);
242 
243       zero_mantissa = (num0|num1) == 0;
244 
245       if (sizeof (unsigned long int) > 6)
246 	{
247 	  numstr = _itoa_word (num1, numbuf + sizeof numbuf, 16,
248 			       info->spec == 'A');
249 	  wnumstr = _itowa_word (num1,
250 				 wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t),
251 				 16, info->spec == 'A');
252 	}
253       else
254 	{
255 	  numstr = _itoa (num1, numbuf + sizeof numbuf, 16,
256 			  info->spec == 'A');
257 	  wnumstr = _itowa (num1,
258 			    wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t),
259 			    16, info->spec == 'A');
260 	}
261 
262       while (numstr > numbuf + (sizeof numbuf - 64 / 4))
263 	{
264 	  *--numstr = '0';
265 	  *--wnumstr = L_('0');
266 	}
267 
268       if (sizeof (unsigned long int) > 6)
269 	{
270 	  numstr = _itoa_word (num0, numstr, 16, info->spec == 'A');
271 	  wnumstr = _itowa_word (num0, wnumstr, 16, info->spec == 'A');
272 	}
273       else
274 	{
275 	  numstr = _itoa (num0, numstr, 16, info->spec == 'A');
276 	  wnumstr = _itowa (num0, wnumstr, 16, info->spec == 'A');
277 	}
278 
279       /* Fill with zeroes.  */
280       while (numstr > numbuf + (sizeof numbuf - 112 / 4))
281 	{
282 	  *--wnumstr = L_('0');
283 	  *--numstr = '0';
284 	}
285 
286       leading = fpnum.ieee.exponent == 0 ? '0' : '1';
287 
288       exponent = fpnum.ieee.exponent;
289 
290       if (exponent == 0)
291 	{
292 	  if (zero_mantissa)
293 	    expnegative = 0;
294 	  else
295 	    {
296 	      /* This is a denormalized number.  */
297 	      expnegative = 1;
298 	      exponent = IEEE854_FLOAT128_BIAS - 1;
299 	    }
300 	}
301       else if (exponent >= IEEE854_FLOAT128_BIAS)
302 	{
303 	  expnegative = 0;
304 	  exponent -= IEEE854_FLOAT128_BIAS;
305 	}
306       else
307 	{
308 	  expnegative = 1;
309 	  exponent = -(exponent - IEEE854_FLOAT128_BIAS);
310 	}
311     }
312 
313   /* Look for trailing zeroes.  */
314   if (! zero_mantissa)
315     {
316       wnumend = &wnumbuf[sizeof wnumbuf / sizeof wnumbuf[0]];
317       numend = &numbuf[sizeof numbuf / sizeof numbuf[0]];
318       while (wnumend[-1] == L_('0'))
319 	{
320 	  --wnumend;
321 	  --numend;
322 	}
323 
324       do_round_away = false;
325 
326       if (precision != -1 && precision < numend - numstr)
327 	{
328 	  char last_digit = precision > 0 ? numstr[precision - 1] : leading;
329 	  char next_digit = numstr[precision];
330 	  int last_digit_value = (last_digit >= 'A' && last_digit <= 'F'
331 				  ? last_digit - 'A' + 10
332 				  : (last_digit >= 'a' && last_digit <= 'f'
333 				     ? last_digit - 'a' + 10
334 				     : last_digit - '0'));
335 	  int next_digit_value = (next_digit >= 'A' && next_digit <= 'F'
336 				  ? next_digit - 'A' + 10
337 				  : (next_digit >= 'a' && next_digit <= 'f'
338 				     ? next_digit - 'a' + 10
339 				     : next_digit - '0'));
340 	  bool more_bits = ((next_digit_value & 7) != 0
341 			    || precision + 1 < numend - numstr);
342 #ifdef HAVE_FENV_H
343 	  int rounding_mode = get_rounding_mode ();
344 	  do_round_away = round_away (negative, last_digit_value & 1,
345 				      next_digit_value >= 8, more_bits,
346 				      rounding_mode);
347 #endif
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