xref: /haiku/src/system/libroot/posix/glibc/stdio-common/printf_fphex.c (revision b55a57da7173b9af0432bd3e148d03f06161d036)
1 /* Print floating point number in hexadecimal notation according to ISO C99.
2    Copyright (C) 1997, 1998, 1999, 2000, 2001 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 int
93 __printf_fphex (FILE *fp,
94 		const struct printf_info *info,
95 		const void *const *args)
96 {
97   /* The floating-point value to output.  */
98   union
99     {
100       union ieee754_double dbl;
101       union ieee854_long_double ldbl;
102     }
103   fpnum;
104 
105   /* Locale-dependent representation of decimal point.	*/
106   const char *decimal;
107   wchar_t decimalwc;
108 
109   /* "NaN" or "Inf" for the special cases.  */
110   const char *special = NULL;
111   const wchar_t *wspecial = NULL;
112 
113   /* Buffer for the generated number string for the mantissa.  The
114      maximal size for the mantissa is 128 bits.  */
115   char numbuf[32];
116   char *numstr;
117   char *numend;
118   wchar_t wnumbuf[32];
119   wchar_t *wnumstr;
120   wchar_t *wnumend;
121   int negative;
122 
123   /* The maximal exponent of two in decimal notation has 5 digits.  */
124   char expbuf[5];
125   char *expstr;
126   wchar_t wexpbuf[5];
127   wchar_t *wexpstr;
128   int expnegative;
129   int exponent;
130 
131   /* Non-zero is mantissa is zero.  */
132   int zero_mantissa;
133 
134   /* The leading digit before the decimal point.  */
135   char leading;
136 
137   /* Precision.  */
138   int precision = info->prec;
139 
140   /* Width.  */
141   int width = info->width;
142 
143   /* Number of characters written.  */
144   int done = 0;
145 
146   /* Nonzero if this is output on a wide character stream.  */
147   int wide = info->wide;
148 
149 
150   /* Figure out the decimal point character.  */
151   if (info->extra == 0)
152     {
153       decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
154       decimalwc = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC);
155     }
156   else
157     {
158       decimal = _NL_CURRENT (LC_MONETARY, MON_DECIMAL_POINT);
159       decimalwc = _NL_CURRENT_WORD (LC_MONETARY,
160 				    _NL_MONETARY_DECIMAL_POINT_WC);
161     }
162   /* The decimal point character must never be zero.  */
163   assert (*decimal != '\0' && decimalwc != L'\0');
164 
165 
166   /* Fetch the argument value.	*/
167 #ifndef __NO_LONG_DOUBLE_MATH
168   if (info->is_long_double && sizeof (long double) > sizeof (double))
169     {
170       fpnum.ldbl.d = *(const long double *) args[0];
171 
172       /* Check for special values: not a number or infinity.  */
173       if (__isnanl (fpnum.ldbl.d))
174 	{
175 	  if (isupper (info->spec))
176 	    {
177 	      special = "NAN";
178 	      wspecial = L"NAN";
179 	    }
180 	  else
181 	    {
182 	      special = "nan";
183 	      wspecial = L"nan";
184 	    }
185 	  negative = 0;
186 	}
187       else
188 	{
189 	  if (__isinfl (fpnum.ldbl.d))
190 	    {
191 	      if (isupper (info->spec))
192 		{
193 		  special = "INF";
194 		  wspecial = L"INF";
195 		}
196 	      else
197 		{
198 		  special = "inf";
199 		  wspecial = L"inf";
200 		}
201 	    }
202 
203 	  negative = signbit (fpnum.ldbl.d);
204 	}
205     }
206   else
207 #endif	/* no long double */
208     {
209       fpnum.dbl.d = *(const double *) args[0];
210 
211       /* Check for special values: not a number or infinity.  */
212       if (__isnan (fpnum.dbl.d))
213 	{
214 	  if (isupper (info->spec))
215 	    {
216 	      special = "NAN";
217 	      wspecial = L"NAN";
218 	    }
219 	  else
220 	    {
221 	      special = "nan";
222 	      wspecial = L"nan";
223 	    }
224 	  negative = 0;
225 	}
226       else
227 	{
228 	  if (__isinf (fpnum.dbl.d))
229 	    {
230 	      if (isupper (info->spec))
231 		{
232 		  special = "INF";
233 		  wspecial = L"INF";
234 		}
235 	      else
236 		{
237 		  special = "inf";
238 		  wspecial = L"inf";
239 		}
240 	    }
241 
242 	  negative = signbit (fpnum.dbl.d);
243 	}
244     }
245 
246   if (special)
247     {
248       int width = info->width;
249 
250       if (negative || info->showsign || info->space)
251 	--width;
252       width -= 3;
253 
254       if (!info->left && width > 0)
255 	PADN (' ', width);
256 
257       if (negative)
258 	outchar ('-');
259       else if (info->showsign)
260 	outchar ('+');
261       else if (info->space)
262 	outchar (' ');
263 
264       PRINT (special, wspecial, 3);
265 
266       if (info->left && width > 0)
267 	PADN (' ', width);
268 
269       return done;
270     }
271 
272   if (info->is_long_double == 0 || sizeof (double) == sizeof (long double))
273     {
274       /* We have 52 bits of mantissa plus one implicit digit.  Since
275 	 52 bits are representable without rest using hexadecimal
276 	 digits we use only the implicit digits for the number before
277 	 the decimal point.  */
278       unsigned long long int num;
279 
280       num = (((unsigned long long int) fpnum.dbl.ieee.mantissa0) << 32
281 	     | fpnum.dbl.ieee.mantissa1);
282 
283       zero_mantissa = num == 0;
284 
285       if (sizeof (unsigned long int) > 6)
286 	{
287 	  wnumstr = _itowa_word (num, wnumbuf + (sizeof wnumbuf) / sizeof (wchar_t), 16,
288 				 info->spec == 'A');
289 	  numstr = _itoa_word (num, numbuf + sizeof numbuf, 16,
290 			       info->spec == 'A');
291 	}
292       else
293 	{
294 	  wnumstr = _itowa (num, wnumbuf + sizeof wnumbuf / sizeof (wchar_t), 16,
295 			    info->spec == 'A');
296 	  numstr = _itoa (num, numbuf + sizeof numbuf, 16,
297 			  info->spec == 'A');
298 	}
299 
300       /* Fill with zeroes.  */
301       while (wnumstr > wnumbuf + (sizeof wnumbuf - 52) / sizeof (wchar_t))
302 	{
303 	  *--wnumstr = L'0';
304 	  *--numstr = '0';
305 	}
306 
307       leading = fpnum.dbl.ieee.exponent == 0 ? '0' : '1';
308 
309       exponent = fpnum.dbl.ieee.exponent;
310 
311       if (exponent == 0)
312 	{
313 	  if (zero_mantissa)
314 	    expnegative = 0;
315 	  else
316 	    {
317 	      /* This is a denormalized number.  */
318 	      expnegative = 1;
319 	      exponent = IEEE754_DOUBLE_BIAS - 1;
320 	    }
321 	}
322       else if (exponent >= IEEE754_DOUBLE_BIAS)
323 	{
324 	  expnegative = 0;
325 	  exponent -= IEEE754_DOUBLE_BIAS;
326 	}
327       else
328 	{
329 	  expnegative = 1;
330 	  exponent = -(exponent - IEEE754_DOUBLE_BIAS);
331 	}
332     }
333 #ifdef PRINT_FPHEX_LONG_DOUBLE
334   else
335     PRINT_FPHEX_LONG_DOUBLE;
336 #endif
337 
338   /* Look for trailing zeroes.  */
339   if (! zero_mantissa)
340     {
341       wnumend = wnumbuf + sizeof wnumbuf;
342       numend = numbuf + sizeof numbuf;
343       while (wnumend[-1] == L'0')
344 	{
345 	  --wnumend;
346 	  --numend;
347 	}
348 
349       if (precision == -1)
350 	precision = numend - numstr;
351       else if (precision < numend - numstr
352 	       && (numstr[precision] > '8'
353 		   || (('A' < '0' || 'a' < '0')
354 		       && numstr[precision] < '0')
355 		   || (numstr[precision] == '8'
356 		       && (precision + 1 < numend - numstr
357 			   /* Round to even.  */
358 			   || (precision > 0
359 			       && ((numstr[precision - 1] & 1)
360 				   ^ (isdigit (numstr[precision - 1]) == 0)))
361 			   || (precision == 0
362 			       && ((leading & 1)
363 				   ^ (isdigit (leading) == 0)))))))
364 	{
365 	  /* Round up.  */
366 	  int cnt = precision;
367 	  while (--cnt >= 0)
368 	    {
369 	      char ch = numstr[cnt];
370 	      /* We assume that the digits and the letters are ordered
371 		 like in ASCII.  This is true for the rest of GNU, too.  */
372 	      if (ch == '9')
373 		{
374 		  wnumstr[cnt] = (wchar_t) info->spec;
375 		  numstr[cnt] = info->spec;	/* This is tricky,
376 		  				   think about it!  */
377 		  break;
378 		}
379 	      else if (tolower (ch) < 'f')
380 		{
381 		  ++numstr[cnt];
382 		  ++wnumstr[cnt];
383 		  break;
384 		}
385 	      else
386 		{
387 		  numstr[cnt] = '0';
388 		  wnumstr[cnt] = L'0';
389 		}
390 	    }
391 	  if (cnt < 0)
392 	    {
393 	      /* The mantissa so far was fff...f  Now increment the
394 		 leading digit.  Here it is again possible that we
395 		 get an overflow.  */
396 	      if (leading == '9')
397 		leading = info->spec;
398 	      else if (tolower (leading) < 'f')
399 		++leading;
400 	      else
401 		{
402 		  leading = 1;
403 		  if (expnegative)
404 		    {
405 		      exponent += 4;
406 		      if (exponent >= 0)
407 			expnegative = 0;
408 		    }
409 		  else
410 		    exponent += 4;
411 		}
412 	    }
413 	}
414     }
415   else
416     {
417       if (precision == -1)
418 	precision = 0;
419       numend = numstr;
420       wnumend = wnumstr;
421     }
422 
423   /* Now we can compute the exponent string.  */
424   expstr = _itoa_word (exponent, expbuf + sizeof expbuf, 10, 0);
425   wexpstr = _itowa_word (exponent,
426 			 wexpbuf + sizeof wexpbuf / sizeof (wchar_t), 10, 0);
427 
428   /* Now we have all information to compute the size.  */
429   width -= ((negative || info->showsign || info->space)
430 	    /* Sign.  */
431 	    + 2    + 1 + 0 + precision + 1 + 1
432 	    /* 0x    h   .   hhh         P   ExpoSign.  */
433 	    + ((expbuf + sizeof expbuf) - expstr));
434 	    /* Exponent.  */
435 
436   /* Count the decimal point.  */
437   if (precision > 0 || info->alt)
438     width -= wide ? 1 : strlen (decimal);
439 
440   /* A special case when the mantissa or the precision is zero and the `#'
441      is not given.  In this case we must not print the decimal point.  */
442   if (precision == 0 && !info->alt)
443     ++width;		/* This nihilates the +1 for the decimal-point
444 			   character in the following equation.  */
445 
446   if (!info->left && width > 0)
447     PADN (' ', width);
448 
449   if (negative)
450     outchar ('-');
451   else if (info->showsign)
452     outchar ('+');
453   else if (info->space)
454     outchar (' ');
455 
456   outchar ('0');
457   if ('X' - 'A' == 'x' - 'a')
458     outchar (info->spec + ('x' - 'a'));
459   else
460     outchar (info->spec == 'A' ? 'X' : 'x');
461   outchar (leading);
462 
463   if (precision > 0 || info->alt)
464     {
465       const wchar_t *wtmp = &decimalwc;
466       PRINT (decimal, wtmp, wide ? 1 : strlen (decimal));
467     }
468 
469   if (precision > 0)
470     {
471       ssize_t tofill = precision - (numend - numstr);
472       PRINT (numstr, wnumstr, MIN (numend - numstr, precision));
473       if (tofill > 0)
474 	PADN ('0', tofill);
475     }
476 
477   if (info->left && info->pad == '0' && width > 0)
478     PADN ('0', width);
479 
480   if ('P' - 'A' == 'p' - 'a')
481     outchar (info->spec + ('p' - 'a'));
482   else
483     outchar (info->spec == 'A' ? 'P' : 'p');
484 
485   outchar (expnegative ? '-' : '+');
486 
487   PRINT (expstr, wexpstr, (expbuf + sizeof expbuf) - expstr);
488 
489   if (info->left && info->pad != '0' && width > 0)
490     PADN (info->pad, width);
491 
492   return done;
493 }
494