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