]>
Commit | Line | Data |
---|---|---|
2f6d1f1b UD |
1 | /* Print floating point number in hexadecimal notation according to |
2 | ISO C 9X. | |
3 | Copyright (C) 1997 Free Software Foundation, Inc. | |
4 | This file is part of the GNU C Library. | |
5 | Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. | |
6 | ||
7 | The GNU C Library is free software; you can redistribute it and/or | |
8 | modify it under the terms of the GNU Library General Public License as | |
9 | published by the Free Software Foundation; either version 2 of the | |
10 | License, or (at your option) any later version. | |
11 | ||
12 | The GNU C Library is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | Library General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU Library General Public | |
18 | License along with the GNU C Library; see the file COPYING.LIB. If not, | |
19 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
20 | Boston, MA 02111-1307, USA. */ | |
21 | ||
22 | #include <ctype.h> | |
23 | #include <ieee754.h> | |
24 | #include <math.h> | |
25 | #include <printf.h> | |
26 | #include <stdlib.h> | |
27 | #include <stdio.h> | |
28 | #include "_itoa.h" | |
29 | #include "../locale/localeinfo.h" | |
30 | ||
31 | /* #define NDEBUG 1*/ /* Undefine this for debugging assertions. */ | |
32 | #include <assert.h> | |
33 | ||
34 | /* This defines make it possible to use the same code for GNU C library and | |
35 | the GNU I/O library. */ | |
36 | #ifdef USE_IN_LIBIO | |
37 | # include <libioP.h> | |
38 | # define PUT(f, s, n) _IO_sputn (f, s, n) | |
39 | # define PAD(f, c, n) _IO_padn (f, c, n) | |
40 | /* We use this file GNU C library and GNU I/O library. So make | |
41 | names equal. */ | |
42 | # undef putc | |
43 | # define putc(c, f) _IO_putc_unlocked (c, f) | |
44 | # define size_t _IO_size_t | |
45 | # define FILE _IO_FILE | |
46 | #else /* ! USE_IN_LIBIO */ | |
47 | # define PUT(f, s, n) fwrite (s, 1, n, f) | |
48 | # define PAD(f, c, n) __printf_pad (f, c, n) | |
49 | ssize_t __printf_pad __P ((FILE *, char pad, int n)); /* In vfprintf.c. */ | |
50 | #endif /* USE_IN_LIBIO */ | |
51 | \f | |
52 | /* Macros for doing the actual output. */ | |
53 | ||
54 | #define outchar(ch) \ | |
55 | do \ | |
56 | { \ | |
57 | register const int outc = (ch); \ | |
58 | if (putc (outc, fp) == EOF) \ | |
59 | return -1; \ | |
60 | ++done; \ | |
61 | } while (0) | |
62 | ||
63 | #define PRINT(ptr, len) \ | |
64 | do \ | |
65 | { \ | |
66 | int outlen = (len); \ | |
67 | const char *cp = (ptr); \ | |
68 | while (outlen-- > 0) \ | |
69 | outchar (*cp++); \ | |
70 | } while (0) | |
71 | ||
72 | #define PADN(ch, len) \ | |
73 | do \ | |
74 | { \ | |
75 | if (PAD (fp, ch, len) != len) \ | |
76 | return -1; \ | |
77 | done += len; \ | |
78 | } \ | |
79 | while (0) | |
80 | \f | |
81 | ||
82 | int | |
83 | __printf_fphex (FILE *fp, | |
84 | const struct printf_info *info, | |
85 | const void *const *args) | |
86 | { | |
87 | /* The floating-point value to output. */ | |
88 | union | |
89 | { | |
90 | union ieee754_double dbl; | |
91 | union ieee854_long_double ldbl; | |
92 | } | |
93 | fpnum; | |
94 | ||
95 | /* Locale-dependent representation of decimal point. */ | |
96 | wchar_t decimal; | |
97 | ||
98 | /* "NaN" or "Inf" for the special cases. */ | |
99 | const char *special = NULL; | |
100 | ||
101 | /* Buffer for the generated number string for the mantissa. The | |
102 | maximal size for the mantissa is 64 bits. */ | |
103 | char numbuf[16]; | |
104 | char *numstr; | |
105 | char *numend; | |
106 | int negative; | |
107 | ||
108 | /* The maximal exponent of two in decimal notation has 5 digits. */ | |
109 | char expbuf[5]; | |
110 | char *expstr; | |
111 | int expnegative; | |
112 | int exponent; | |
113 | ||
114 | /* Non-zero is mantissa is zero. */ | |
115 | int zero_mantissa; | |
116 | ||
117 | /* The leading digit before the decimal point. */ | |
118 | char leading; | |
119 | ||
120 | /* Precision. */ | |
121 | int precision = info->prec; | |
122 | ||
123 | /* Width. */ | |
124 | int width = info->width; | |
125 | ||
126 | /* Number of characters written. */ | |
127 | int done = 0; | |
128 | ||
129 | ||
130 | /* Figure out the decimal point character. */ | |
131 | if (info->extra == 0) | |
132 | { | |
133 | if (mbtowc (&decimal, _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT), | |
134 | strlen (_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT))) <= 0) | |
135 | decimal = (wchar_t) *_NL_CURRENT (LC_NUMERIC, DECIMAL_POINT); | |
136 | } | |
137 | else | |
138 | { | |
139 | if (mbtowc (&decimal, _NL_CURRENT (LC_MONETARY, MON_DECIMAL_POINT), | |
140 | strlen (_NL_CURRENT (LC_MONETARY, MON_DECIMAL_POINT))) <= 0) | |
141 | decimal = (wchar_t) *_NL_CURRENT (LC_MONETARY, MON_DECIMAL_POINT); | |
142 | } | |
143 | /* Give default value. */ | |
144 | if (decimal == L'\0') | |
145 | decimal = L'.'; | |
146 | ||
147 | ||
148 | /* Fetch the argument value. */ | |
149 | if (info->is_long_double && sizeof (long double) > sizeof (double)) | |
150 | { | |
151 | fpnum.ldbl.d = *(const long double *) args[0]; | |
152 | ||
153 | /* Check for special values: not a number or infinity. */ | |
154 | if (__isnanl (fpnum.ldbl.d)) | |
155 | { | |
156 | special = isupper (info->spec) ? "NAN" : "nan"; | |
157 | negative = 0; | |
158 | } | |
159 | else | |
160 | { | |
161 | if (__isinfl (fpnum.ldbl.d)) | |
162 | special = isupper (info->spec) ? "INF" : "inf"; | |
163 | ||
164 | negative = fpnum.ldbl.d < 0; | |
165 | } | |
166 | } | |
167 | else | |
168 | { | |
169 | fpnum.dbl.d = *(const double *) args[0]; | |
170 | ||
171 | /* Check for special values: not a number or infinity. */ | |
172 | if (__isnan (fpnum.dbl.d)) | |
173 | { | |
174 | special = isupper (info->spec) ? "NAN" : "nan"; | |
175 | negative = 0; | |
176 | } | |
177 | else | |
178 | { | |
179 | if (__isinf (fpnum.dbl.d)) | |
180 | special = isupper (info->spec) ? "INF" : "inf"; | |
181 | ||
182 | negative = fpnum.dbl.d < 0; | |
183 | } | |
184 | } | |
185 | ||
186 | if (special) | |
187 | { | |
188 | int width = info->prec > info->width ? info->prec : info->width; | |
189 | ||
190 | if (negative || info->showsign || info->space) | |
191 | --width; | |
192 | width -= 3; | |
193 | ||
194 | if (!info->left && width > 0) | |
195 | PADN (' ', width); | |
196 | ||
197 | if (negative) | |
198 | outchar ('-'); | |
199 | else if (info->showsign) | |
200 | outchar ('+'); | |
201 | else if (info->space) | |
202 | outchar (' '); | |
203 | ||
204 | PRINT (special, 3); | |
205 | ||
206 | if (info->left && width > 0) | |
207 | PADN (' ', width); | |
208 | ||
209 | return done; | |
210 | } | |
211 | ||
212 | /* We are handling here only 64 and 80 bit IEEE foating point | |
213 | numbers. */ | |
214 | if (info->is_long_double == 0 || sizeof (double) == sizeof (long double)) | |
215 | { | |
216 | /* We have 52 bits of mantissa plus one implicit digit. Since | |
217 | 52 bits are representable without rest using hexadecimal | |
218 | digits we use only the implicit digits for the number before | |
219 | the decimal point. */ | |
377a515b | 220 | unsigned long long int num; |
2f6d1f1b | 221 | |
377a515b UD |
222 | num = (((unsigned long long int) fpnum.dbl.ieee.mantissa0) << 32 |
223 | | fpnum.dbl.ieee.mantissa1); | |
2f6d1f1b | 224 | |
377a515b | 225 | zero_mantissa = num == 0; |
2f6d1f1b | 226 | |
377a515b UD |
227 | if (sizeof (unsigned long int) > 6) |
228 | numstr = _itoa_word (num, numbuf + sizeof numbuf, 16, | |
229 | info->spec == 'A'); | |
2f6d1f1b | 230 | else |
377a515b UD |
231 | numstr = _itoa (num, numbuf + sizeof numbuf, 16, |
232 | info->spec == 'A'); | |
2f6d1f1b UD |
233 | |
234 | /* Fill with zeroes. */ | |
235 |