OSDN Git Service

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