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