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