xref: /haiku/src/system/libroot/posix/glibc/stdio-common/printf_fphex.c (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
1 /* Print floating point number in hexadecimal notation according to ISO C99.
2    Copyright (C) 1997-2002,2004,2006 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, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20 
21 #include <ctype.h>
22 #include <ieee754.h>
23 #include <math.h>
24 #include <printf.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <wchar.h>
29 #include "_itoa.h"
30 #include "_itowa.h"
31 #include <locale/localeinfo.h>
32 
33 /* #define NDEBUG 1*/		/* Undefine this for debugging assertions.  */
34 #include <assert.h>
35 
36 /* This defines make it possible to use the same code for GNU C library and
37    the GNU I/O library.	 */
38 #ifdef USE_IN_LIBIO
39 # include <libioP.h>
40 # define PUT(f, s, n) _IO_sputn (f, s, n)
41 # define PAD(f, c, n) (wide ? _IO_wpadn (f, c, n) : _IO_padn (f, c, n))
42 /* We use this file GNU C library and GNU I/O library.	So make
43    names equal.	 */
44 # undef putc
45 # define putc(c, f) (wide \
46 		     ? (int)_IO_putwc_unlocked (c, f) : _IO_putc_unlocked (c, f))
47 # define size_t     _IO_size_t
48 # define FILE	     _IO_FILE
49 #else	/* ! USE_IN_LIBIO */
50 # define PUT(f, s, n) fwrite (s, 1, n, f)
51 # define PAD(f, c, n) __printf_pad (f, c, n)
52 ssize_t __printf_pad __P ((FILE *, char pad, int n)); /* In vfprintf.c.  */
53 #endif	/* USE_IN_LIBIO */
54 
55 /* Macros for doing the actual output.  */
56 
57 #define outchar(ch)							      \
58   do									      \
59     {									      \
60       register const int outc = (ch);					      \
61       if (putc (outc, fp) == EOF)					      \
62 	return -1;							      \
63       ++done;								      \
64     } while (0)
65 
66 #define PRINT(ptr, wptr, len)						      \
67   do									      \
68     {									      \
69       register size_t outlen = (len);					      \
70       if (wide)								      \
71 	while (outlen-- > 0)						      \
72 	  outchar (*wptr++);						      \
73       else								      \
74 	while (outlen-- > 0)						      \
75 	  outchar (*ptr++);						      \
76     } while (0)
77 
78 #define PADN(ch, len)							      \
79   do									      \
80     {									      \
81       if (PAD (fp, ch, len) != len)					      \
82 	return -1;							      \
83       done += len;							      \
84     }									      \
85   while (0)
86 
87 #ifndef MIN
88 # define MIN(a,b) ((a)<(b)?(a):(b))
89 #endif
90 
91 
92 
93 #ifdef __x86_64__
94 
95 /* sysdeps/x86_64/fpu/printf_fphex.c */
96 
97 #ifndef LONG_DOUBLE_DENORM_BIAS
98 # define LONG_DOUBLE_DENORM_BIAS (IEEE854_LONG_DOUBLE_BIAS - 1)
99 #endif
100 
101 #define PRINT_FPHEX_LONG_DOUBLE \
102 do {									      \
103       /* The "strange" 80 bit format on ix86 and m68k has an explicit	      \
104 	 leading digit in the 64 bit mantissa.  */			      \
105       unsigned long long int num;					      \
106 									      \
107 									      \
108       num = (((unsigned long long int) fpnum.ldbl.ieee.mantissa0) << 32	      \
109 	     | fpnum.ldbl.ieee.mantissa1);				      \
110 									      \
111       zero_mantissa = num == 0;						      \
112 									      \
113       if (sizeof (unsigned long int) > 6)				      \
114 	{								      \
115 	  numstr = _itoa_word (num, numbuf + sizeof numbuf, 16,		      \
116 			       info->spec == 'A');			      \
117 	  wnumstr = _itowa_word (num,					      \
118 				 wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t),\
119 				 16, info->spec == 'A');		      \
120 	}								      \
121       else								      \
122 	{								      \
123 	  numstr = _itoa (num, numbuf + sizeof numbuf, 16, info->spec == 'A');\
124 	  wnumstr = _itowa (num,					      \
125 			    wnumbuf + sizeof (wnumbuf) / sizeof (wchar_t),    \
126 			    16, info->spec == 'A');			      \
127 	}								      \
128 									      \
129       /* Fill with zeroes.  */						      \
130       while (numstr > numbuf + (sizeof numbuf - 64 / 4))		      \
131 	{								      \
132 	  *--numstr = '0';						      \
133 	  *--wnumstr = L'0';						      \
134 	}								      \
135 									      \
136       /* We use a full nibble for the leading digit.  */		      \
137       leading = *numstr++;						      \
138 									      \
139       /* We have 3 bits from the mantissa in the leading nibble.	      \
140 	 Therefore we are here using `IEEE854_LONG_DOUBLE_BIAS + 3'.  */      \
141       exponent = fpnum.ldbl.ieee.exponent;				      \
142 									      \
143       if (exponent == 0)						      \
144 	{								      \
145 	  if (zero_mantissa)						      \
146 	    expnegative = 0;						      \
147 	  else								      \
148 	    {								      \
149 	      /* This is a denormalized number.  */			      \
150 	      expnegative = 1;						      \
151 	      /* This is a hook for the m68k long double format, where the    \
152 		 exponent bias is the same for normalized and denormalized    \
153 		 numbers.  */						      \
154 	      exponent = LONG_DOUBLE_DENORM_BIAS + 3;			      \
155 	    }								      \
156 	}								      \
157       else if (exponent >= IEEE854_LONG_DOUBLE_BIAS + 3)		      \
158 	{								      \
159 	  expnegative = 0;						      \
160 	  exponent -= IEEE854_LONG_DOUBLE_BIAS + 3;			      \
161 	}								      \
162       else								      \
163 	{								      \
164 	  expnegative = 1;						      \
165 	  exponent = -(exponent - (IEEE854_LONG_DOUBLE_BIAS + 3));	      \
166 	}								      \
167 } while (0)
168 
169 #endif	/* __x86_64__ */
170 
171 
172 int
173 __printf_fphex (FILE *fp,
174 		const struct printf_info *info,
175 		const void *const *args)
176 {
177   /* The floating-point value to output.  */
178   union
179     {
180       union ieee754_double dbl;
181       union ieee854_long_double ldbl;
182     }
183   fpnum;
184 
185   /* Locale-dependent representation of decimal point.	*/
186   const char *decimal;
187   wchar_t decimalwc;
188 
189   /* "NaN" or "Inf" for the special cases.  */
190   const char *special = NULL;
191   const wchar_t *wspecial = NULL;
192 
193   /* Buffer for the generated number string for the mantissa.  The
194      maximal size for the mantissa is 128 bits.  */
195   char numbuf[32];
196   char *numstr;
197   char *numend;
198   wchar_t wnumbuf[32];
199   wchar_t *wnumstr;
200   wchar_t *wnumend;
201   int negative;
202 
203   /* The maximal exponent of two in decimal notation has 5 digits.  */
204   char expbuf[5];
205   char *expstr;
206   wchar_t wexpbuf[5];
207   wchar_t *wexpstr;
208   int expnegative;
209   int exponent;
210 
211   /* Non-zero is mantissa is zero.  */
212   int zero_mantissa;
213 
214   /* The leading digit before the decimal point.  */
215   char leading;
216 
217   /* Precision.  */
218   int precision = info->prec;
219 
220   /* Width.  */
221   int width = info->width;
222 
223   /* Number of characters written.  */
224   int done = 0;
225 
226   /* Nonzero if this is output on a wide character stream.  */
227   int wide = info->wide;
228 
229 
230   /* Figure out the decimal point character.  */
231   if (info->extra == 0)
232     {
233       decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
234       decimalwc = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC);
235     }
236   else
237     {
238       decimal = _NL_CURRENT (LC_MONETARY, MON_DECIMAL_POINT);
239       decimalwc = _NL_CURRENT_WORD (LC_MONETARY,
240 				    _NL_MONETARY_DECIMAL_POINT_WC);
241     }
242   /* The decimal point character must never be zero.  */
243   assert (*decimal != '\0' && decimalwc != L'\0');
244 
245 
246   /* Fetch the argument value.	*/
247 #ifndef __NO_LONG_DOUBLE_MATH
248   if (info->is_long_double && sizeof (long double) > sizeof (double))
249     {
250       fpnum.ldbl.d = *(const long double *) args[0];
251 
252       /* Check for special values: not a number or infinity.  */
253       if (__isnanl (fpnum.ldbl.d))
254 	{
255 	  if (isupper (info->spec))
256 	    {
257 	      special = "NAN";
258 	      wspecial = L"NAN";
259 	    }
260 	  else
261 	    {
262 	      special = "nan";
263 	      wspecial = L"nan";
264 	    }
265 	  negative = 0;
266 	}
267       else
268 	{
269 	  if (__isinfl (fpnum.ldbl.d))
270 	    {
271 	      if (isupper (info->spec))
272 		{
273 		  special = "INF";
274 		  wspecial = L"INF";
275 		}
276 	      else
277 		{
278 		  special = "inf";
279 		  wspecial = L"inf";
280 		}
281 	    }
282 
283 	  negative = signbit (fpnum.ldbl.d);
284 	}
285     }
286   else
287 #endif	/* no long double */
288     {
289       fpnum.dbl.d = *(const double *) args[0];
290 
291       /* Check for special values: not a number or infinity.  */
292       if (__isnan (fpnum.dbl.d))
293 	{
294 	  if (isupper (info->spec))
295 	    {
296 	      special = "NAN";
297 	      wspecial = L"NAN";
298 	    }
299 	  else
300 	    {
301 	      special = "nan";
302 	      wspecial = L"nan";
303 	    }
304 	  negative = 0;
305 	}
306       else
307 	{
308 	  if (__isinf (fpnum.dbl.d))
309 	    {
310 	      if (isupper (info->spec))
311 		{
312 		  special = "INF";
313 		  wspecial = L"INF";
314 		}
315 	      else
316 		{
317 		  special = "inf";
318 		  wspecial = L"inf";
319 		}
320 	    }
321 
322 	  negative = signbit (fpnum.dbl.d);
323 	}
324     }
325 
326   if (special)
327     {
328       int width = info->width;
329 
330       if (negative || info->showsign || info->space)
331 	--width;
332       width -= 3;
333 
334       if (!info->left && width > 0)
335 	PADN (' ', width);
336 
337       if (negative)
338 	outchar ('-');
339       else if (info->showsign)
340 	outchar ('+');
341       else if (info->space)
342 	outchar (' ');
343 
344       PRINT (special, wspecial, 3);
345 
346       if (info->left && width > 0)
347 	PADN (' ', width);
348 
349       return done;
350     }
351 
352   if (info->is_long_double == 0 || sizeof (double) == sizeof (long double))
353     {
354       /* We have 52 bits of mantissa plus one implicit digit.  Since
355 	 52 bits are representable without rest using hexadecimal
356 	 digits we use only the implicit digits for the number before
357 	 the decimal point.  */
358       unsigned long long int num;
359 
360       num = (((unsigned long long int) fpnum.dbl.ieee.mantissa0) << 32
361 	     | fpnum.dbl.ieee.mantissa1);
362 
363       zero_mantissa = num == 0;
364 
365       if (sizeof (unsigned long int) > 6)
366 	{
367 	  wnumstr = _itowa_word (num, wnumbuf + (sizeof wnumbuf) / sizeof (wchar_t), 16,
368 				 info->spec == 'A');
369 	  numstr = _itoa_word (num, numbuf + sizeof numbuf, 16,
370 			       info->spec == 'A');
371 	}
372       else
373 	{
374 	  wnumstr = _itowa (num, wnumbuf + sizeof wnumbuf / sizeof (wchar_t), 16,
375 			    info->spec == 'A');
376 	  numstr = _itoa (num, numbuf + sizeof numbuf, 16,
377 			  info->spec == 'A');
378 	}
379 
380       /* Fill with zeroes.  */
381       while (wnumstr > wnumbuf + (sizeof wnumbuf - 52) / sizeof (wchar_t))
382 	{
383 	  *--wnumstr = L'0';
384 	  *--numstr = '0';
385 	}
386 
387       leading = fpnum.dbl.ieee.exponent == 0 ? '0' : '1';
388 
389       exponent = fpnum.dbl.ieee.exponent;
390 
391       if (exponent == 0)
392 	{
393 	  if (zero_mantissa)
394 	    expnegative = 0;
395 	  else
396 	    {
397 	      /* This is a denormalized number.  */
398 	      expnegative = 1;
399 	      exponent = IEEE754_DOUBLE_BIAS - 1;
400 	    }
401 	}
402       else if (exponent >= IEEE754_DOUBLE_BIAS)
403 	{
404 	  expnegative = 0;
405 	  exponent -= IEEE754_DOUBLE_BIAS;
406 	}
407       else
408 	{
409 	  expnegative = 1;
410 	  exponent = -(exponent - IEEE754_DOUBLE_BIAS);
411 	}
412     }
413 #ifdef PRINT_FPHEX_LONG_DOUBLE
414   else
415     PRINT_FPHEX_LONG_DOUBLE;
416 #endif
417 
418   /* Look for trailing zeroes.  */
419   if (! zero_mantissa)
420     {
421       wnumend = &wnumbuf[sizeof wnumbuf / sizeof wnumbuf[0]];
422       numend = &numbuf[sizeof numbuf / sizeof numbuf[0]];
423       while (wnumend[-1] == L'0')
424 	{
425 	  --wnumend;
426 	  --numend;
427 	}
428 
429       if (precision == -1)
430 	precision = numend - numstr;
431       else if (precision < numend - numstr
432 	       && (numstr[precision] > '8'
433 		   || (('A' < '0' || 'a' < '0')
434 		       && numstr[precision] < '0')
435 		   || (numstr[precision] == '8'
436 		       && (precision + 1 < numend - numstr
437 			   /* Round to even.  */
438 			   || (precision > 0
439 			       && ((numstr[precision - 1] & 1)
440 				   ^ (isdigit (numstr[precision - 1]) == 0)))
441 			   || (precision == 0
442 			       && ((leading & 1)
443 				   ^ (isdigit (leading) == 0)))))))
444 	{
445 	  /* Round up.  */
446 	  int cnt = precision;
447 	  while (--cnt >= 0)
448 	    {
449 	      char ch = numstr[cnt];
450 	      /* We assume that the digits and the letters are ordered
451 		 like in ASCII.  This is true for the rest of GNU, too.  */
452 	      if (ch == '9')
453 		{
454 		  wnumstr[cnt] = (wchar_t) info->spec;
455 		  numstr[cnt] = info->spec;	/* This is tricky,
456 		  				   think about it!  */
457 		  break;
458 		}
459 	      else if (tolower (ch) < 'f')
460 		{
461 		  ++numstr[cnt];
462 		  ++wnumstr[cnt];
463 		  break;
464 		}
465 	      else
466 		{
467 		  numstr[cnt] = '0';
468 		  wnumstr[cnt] = L'0';
469 		}
470 	    }
471 	  if (cnt < 0)
472 	    {
473 	      /* The mantissa so far was fff...f  Now increment the
474 		 leading digit.  Here it is again possible that we
475 		 get an overflow.  */
476 	      if (leading == '9')
477 		leading = info->spec;
478 	      else if (tolower (leading) < 'f')
479 		++leading;
480 	      else
481 		{
482 		  leading = '1';
483 		  if (expnegative)
484 		    {
485 		      exponent -= 4;
486 		      if (exponent <= 0)
487 			{
488 			  exponent = -exponent;
489 			  expnegative = 0;
490 			}
491 		    }
492 		  else
493 		    exponent += 4;
494 		}
495 	    }
496 	}
497     }
498   else
499     {
500       if (precision == -1)
501 	precision = 0;
502       numend = numstr;
503       wnumend = wnumstr;
504     }
505 
506   /* Now we can compute the exponent string.  */
507   expstr = _itoa_word (exponent, expbuf + sizeof expbuf, 10, 0);
508   wexpstr = _itowa_word (exponent,
509 			 wexpbuf + sizeof wexpbuf / sizeof (wchar_t), 10, 0);
510 
511   /* Now we have all information to compute the size.  */
512   width -= ((negative || info->showsign || info->space)
513 	    /* Sign.  */
514 	    + 2    + 1 + 0 + precision + 1 + 1
515 	    /* 0x    h   .   hhh         P   ExpoSign.  */
516 	    + ((expbuf + sizeof expbuf) - expstr));
517 	    /* Exponent.  */
518 
519   /* Count the decimal point.
520      A special case when the mantissa or the precision is zero and the `#'
521      is not given.  In this case we must not print the decimal point.  */
522   if (precision > 0 || info->alt)
523     width -= wide ? 1 : strlen (decimal);
524 
525   if (!info->left && info->pad != '0' && width > 0)
526     PADN (' ', width);
527 
528   if (negative)
529     outchar ('-');
530   else if (info->showsign)
531     outchar ('+');
532   else if (info->space)
533     outchar (' ');
534 
535   outchar ('0');
536   if ('X' - 'A' == 'x' - 'a')
537     outchar (info->spec + ('x' - 'a'));
538   else
539     outchar (info->spec == 'A' ? 'X' : 'x');
540 
541   if (!info->left && info->pad == '0' && width > 0)
542     PADN ('0', width);
543 
544   outchar (leading);
545 
546   if (precision > 0 || info->alt)
547     {
548       const wchar_t *wtmp = &decimalwc;
549       PRINT (decimal, wtmp, wide ? 1 : strlen (decimal));
550     }
551 
552   if (precision > 0)
553     {
554       ssize_t tofill = precision - (numend - numstr);
555       PRINT (numstr, wnumstr, MIN (numend - numstr, precision));
556       if (tofill > 0)
557 	PADN ('0', tofill);
558     }
559 
560   if ('P' - 'A' == 'p' - 'a')
561     outchar (info->spec + ('p' - 'a'));
562   else
563     outchar (info->spec == 'A' ? 'P' : 'p');
564 
565   outchar (expnegative ? '-' : '+');
566 
567   PRINT (expstr, wexpstr, (expbuf + sizeof expbuf) - expstr);
568 
569   if (info->left && info->pad != '0' && width > 0)
570     PADN (info->pad, width);
571 
572   return done;
573 }
574