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