6711ccc82b1f148a869e979725fd31292e626e79
[platform/upstream/glibc.git] / stdio-common / printf_fphex.c
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) : INTUSE(_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 (FILE *, char pad, int n) __THROW; /* In vfprintf.c.  */
53 #endif  /* USE_IN_LIBIO */
54 \f
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 \f
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 / sizeof wnumbuf[0]];
342       numend = &numbuf[sizeof numbuf / sizeof numbuf[0]];
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      A special case when the mantissa or the precision is zero and the `#'
438      is not given.  In this case we must not print the decimal point.  */
439   if (precision > 0 || info->alt)
440     width -= wide ? 1 : strlen (decimal);
441
442   if (!info->left && info->pad != '0' && width > 0)
443     PADN (' ', width);
444
445   if (negative)
446     outchar ('-');
447   else if (info->showsign)
448     outchar ('+');
449   else if (info->space)
450     outchar (' ');
451
452   outchar ('0');
453   if ('X' - 'A' == 'x' - 'a')
454     outchar (info->spec + ('x' - 'a'));
455   else
456     outchar (info->spec == 'A' ? 'X' : 'x');
457
458   if (!info->left && info->pad == '0' && width > 0)
459     PADN ('0', width);
460
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 ('P' - 'A' == 'p' - 'a')
478     outchar (info->spec + ('p' - 'a'));
479   else
480     outchar (info->spec == 'A' ? 'P' : 'p');
481
482   outchar (expnegative ? '-' : '+');
483
484   PRINT (expstr, wexpstr, (expbuf + sizeof expbuf) - expstr);
485
486   if (info->left && info->pad != '0' && width > 0)
487     PADN (info->pad, width);
488
489   return done;
490 }