]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/generic/printf_fphex.c
* posix/regcomp.c (re_comp): Call __regfree on re_comp_buf.
[thirdparty/glibc.git] / sysdeps / generic / printf_fphex.c
CommitLineData
a1d84548 1/* Print floating point number in hexadecimal notation according to ISO C99.
77fe0b9c 2 Copyright (C) 1997,1998,1999,2000,2001,2002 Free Software Foundation, Inc.
2f6d1f1b
UD
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
41bdb6e2
AJ
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.
2f6d1f1b
UD
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
41bdb6e2 14 Lesser General Public License for more details.
2f6d1f1b 15
41bdb6e2
AJ
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. */
2f6d1f1b
UD
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>
f671aeab 27#include <string.h>
8d8c6efa 28#include <wchar.h>
2f6d1f1b 29#include "_itoa.h"
a1d84548 30#include "_itowa.h"
8f2ece69 31#include <locale/localeinfo.h>
2f6d1f1b
UD
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)
77fe0b9c 41# define PAD(f, c, n) (wide ? _IO_wpadn (f, c, n) : INTUSE(_IO_padn) (f, c, n))
2f6d1f1b
UD
42/* We use this file GNU C library and GNU I/O library. So make
43 names equal. */
44# undef putc
d64b6ad0 45# define putc(c, f) (wide \
1dc72e4f 46 ? (int)_IO_putwc_unlocked (c, f) : _IO_putc_unlocked (c, f))
2f6d1f1b
UD
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)
52ssize_t __printf_pad __P ((FILE *, char pad, int n)); /* 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
a1d84548 66#define PRINT(ptr, wptr, len) \
2f6d1f1b
UD
67 do \
68 { \
a1d84548
UD
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++); \
2f6d1f1b
UD
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)
0d8733c4
UD
86
87#ifndef MIN
88# define MIN(a,b) ((a)<(b)?(a):(b))
89#endif
2f6d1f1b
UD
90\f
91
92int
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. */
a1d84548
UD
106 const char *decimal;
107 wchar_t decimalwc;
2f6d1f1b
UD
108
109 /* "NaN" or "Inf" for the special cases. */
110 const char *special = NULL;
a1d84548 111 const wchar_t *wspecial = NULL;
2f6d1f1b
UD
112
113 /* Buffer for the generated number string for the mantissa. The
abfbdde1
UD
114 maximal size for the mantissa is 128 bits. */
115 char numbuf[32];
2f6d1f1b
UD
116 char *numstr;
117 char *numend;
a1d84548
UD
118 wchar_t wnumbuf[32];
119 wchar_t *wnumstr;
120 wchar_t *wnumend;
2f6d1f1b
UD
121 int negative;
122
123 /* The maximal exponent of two in decimal notation has 5 digits. */
124 char expbuf[5];
125 char *expstr;
a1d84548
UD
126 wchar_t wexpbuf[5];
127 wchar_t *wexpstr;
2f6d1f1b
UD
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
d64b6ad0
UD
146 /* Nonzero if this is output on a wide character stream. */
147 int wide = info->wide;
148
2f6d1f1b
UD
149
150 /* Figure out the decimal point character. */
151 if (info->extra == 0)
152 {
a1d84548
UD
153 decimal = _NL_CURRENT (LC_NUMERIC, DECIMAL_POINT);
154 decimalwc = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC);
2f6d1f1b
UD
155 }
156 else
157 {
a1d84548
UD
158 decimal = _NL_CURRENT (LC_MONETARY, MON_DECIMAL_POINT);
159 decimalwc = _NL_CURRENT_WORD (LC_MONETARY,
160 _NL_MONETARY_DECIMAL_POINT_WC);
2f6d1f1b 161 }
a1d84548
UD
162 /* The decimal point character must never be zero. */
163 assert (*decimal != '\0' && decimalwc != L'\0');
2f6d1f1b
UD
164
165
166 /* Fetch the argument value. */
f98b4bbd 167#ifndef __NO_LONG_DOUBLE_MATH
2f6d1f1b
UD
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. */
76f2646f 173 if (__isnanl (fpnum.ldbl.d))
2f6d1f1b 174 {
a1d84548
UD
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 }
2f6d1f1b
UD
185 negative = 0;
186 }
187 else
188 {
76f2646f 189 if (__isinfl (fpnum.ldbl.d))
a1d84548
UD
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 }
2f6d1f1b 202
f43ce637 203 negative = signbit (fpnum.ldbl.d);
2f6d1f1b
UD
204 }
205 }
206 else
f98b4bbd 207#endif /* no long double */
2f6d1f1b
UD
208 {
209 fpnum.dbl.d = *(const double *) args[0];
210
211 /* Check for special values: not a number or infinity. */
76f2646f 212 if (__isnan (fpnum.dbl.d))
2f6d1f1b 213 {
a1d84548
UD
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 }
2f6d1f1b
UD
224 negative = 0;
225 }
226 else
227 {
76f2646f 228 if (__isinf (fpnum.dbl.d))
a1d84548
UD
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 }
2f6d1f1b 241
f43ce637 242 negative = signbit (fpnum.dbl.d);
2f6d1f1b
UD
243 }
244 }
245
246 if (special)
247 {
1f205a47 248 int width = info->width;
2f6d1f1b
UD
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
a1d84548 264 PRINT (special, wspecial, 3);
2f6d1f1b
UD
265
266 if (info->left && width > 0)
267 PADN (' ', width);
268
269 return done;
270 }
271
2f6d1f1b
UD
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. */
377a515b 278 unsigned long long int num;
2f6d1f1b 279
377a515b
UD
280 num = (((unsigned long long int) fpnum.dbl.ieee.mantissa0) << 32
281 | fpnum.dbl.ieee.mantissa1);
2f6d1f1b 282
377a515b 283 zero_mantissa = num == 0;
2f6d1f1b 284
377a515b 285 if (sizeof (unsigned long int) > 6)
a1d84548 286 {
a535ce14 287 wnumstr = _itowa_word (num, wnumbuf + (sizeof wnumbuf) / sizeof (wchar_t), 16,
a1d84548
UD
288 info->spec == 'A');
289 numstr = _itoa_word (num, numbuf + sizeof numbuf, 16,
290 info->spec == 'A');
291 }
2f6d1f1b 292 else
a1d84548 293 {
a535ce14 294 wnumstr = _itowa (num, wnumbuf + sizeof wnumbuf / sizeof (wchar_t), 16,
a1d84548
UD
295 info->spec == 'A');
296 numstr = _itoa (num, numbuf + sizeof numbuf, 16,
297 info->spec == 'A');
298 }
2f6d1f1b
UD
299
300 /* Fill with zeroes. */
a535ce14 301 while (wnumstr > wnumbuf + (sizeof wnumbuf - 52) / sizeof (wchar_t))
a1d84548
UD
302 {
303 *--wnumstr = L'0';
304 *--numstr = '0';
305 }
2f6d1f1b
UD
306
307 leading = fpnum.dbl.ieee.exponent == 0 ? '0' : '1';
308
309 exponent = fpnum.dbl.ieee.exponent;
310
d8cceb4f 311 if (exponent == 0)
2f6d1f1b 312 {
d8cceb4f
UD
313 if (zero_mantissa)
314 expnegative = 0;
315 else
316 {
317 /* This is a denormalized number. */
318 expnegative = 1;
91ea72b7 319 exponent = IEEE754_DOUBLE_BIAS - 1;
d8cceb4f 320 }
2f6d1f1b 321 }
d8cceb4f 322 else if (exponent >= IEEE754_DOUBLE_BIAS)
2f6d1f1b
UD
323 {
324 expnegative = 0;
d8cceb4f
UD
325 exponent -= IEEE754_DOUBLE_BIAS;
326 }
327 else
328 {
329 expnegative = 1;
330 exponent = -(exponent - IEEE754_DOUBLE_BIAS);
2f6d1f1b
UD
331 }
332 }
abfbdde1 333#ifdef PRINT_FPHEX_LONG_DOUBLE
2f6d1f1b 334 else
abfbdde1 335 PRINT_FPHEX_LONG_DOUBLE;
91ea72b7 336#endif
2f6d1f1b
UD
337
338 /* Look for trailing zeroes. */
339 if (! zero_mantissa)
340 {
a1d84548 341 wnumend = wnumbuf + sizeof wnumbuf;
2f6d1f1b 342 numend = numbuf + sizeof numbuf;
a1d84548
UD
343 while (wnumend[-1] == L'0')
344 {
345 --wnumend;
346 --numend;
347 }
2f6d1f1b
UD
348
349 if (precision == -1)
350 precision = numend - numstr;
351 else if (precision < numend - numstr
9756dfe1
UD
352 && (numstr[precision] > '8'
353 || (('A' < '0' || 'a' < '0')
354 && numstr[precision] < '0')
355 || (numstr[precision] == '8'
2f6d1f1b
UD
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 {
a1d84548 374 wnumstr[cnt] = (wchar_t) info->spec;
2f6d1f1b 375 numstr[cnt] = info->spec; /* This is tricky,
a1d84548 376 think about it! */
2f6d1f1b
UD
377 break;
378 }
379 else if (tolower (ch) < 'f')
380 {
381 ++numstr[cnt];
a1d84548 382 ++wnumstr[cnt];
2f6d1f1b
UD
383 break;
384 }
385 else
a1d84548
UD
386 {
387 numstr[cnt] = '0';
388 wnumstr[cnt] = L'0';
389 }
2f6d1f1b
UD
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
263456bd
UD
416 {
417 if (precision == -1)
418 precision = 0;
419 numend = numstr;
a1d84548 420 wnumend = wnumstr;
263456bd 421 }
2f6d1f1b
UD
422
423 /* Now we can compute the exponent string. */
424 expstr = _itoa_word (exponent, expbuf + sizeof expbuf, 10, 0);
66bdfcab
UD
425 wexpstr = _itowa_word (exponent,
426 wexpbuf + sizeof wexpbuf / sizeof (wchar_t), 10, 0);
2f6d1f1b
UD
427
428 /* Now we have all information to compute the size. */
429 width -= ((negative || info->showsign || info->space)
430 /* Sign. */
b15cb495 431 + 2 + 1 + 0 + precision + 1 + 1
2f6d1f1b
UD
432 /* 0x h . hhh P ExpoSign. */
433 + ((expbuf + sizeof expbuf) - expstr));
434 /* Exponent. */
435
b15cb495
UD
436 /* Count the decimal point. */
437 if (precision > 0 || info->alt)
438 width -= wide ? 1 : strlen (decimal);
439
29329ef5
UD
440 /* A special case when the mantissa or the precision is zero and the `#'
441 is not given. In this case we must not print the decimal point. */
263456bd 442 if (precision == 0 && !info->alt)
2f6d1f1b
UD
443 ++width; /* This nihilates the +1 for the decimal-point
444 character in the following equation. */
445
446 if (!info->left && width > 0)
447 PADN (' ', width);
448
449 if (negative)
450 outchar ('-');
451 else if (info->showsign)
452 outchar ('+');
453 else if (info->space)
454 outchar (' ');
455
456 outchar ('0');
263456bd
UD
457 if ('X' - 'A' == 'x' - 'a')
458 outchar (info->spec + ('x' - 'a'));
459 else
460 outchar (info->spec == 'A' ? 'X' : 'x');
2f6d1f1b
UD
461 outchar (leading);
462
263456bd 463 if (precision > 0 || info->alt)
a1d84548
UD
464 {
465 const wchar_t *wtmp = &decimalwc;
466 PRINT (decimal, wtmp, wide ? 1 : strlen (decimal));
467 }
2f6d1f1b 468
263456bd 469 if (precision > 0)
2f6d1f1b 470 {
b15cb495 471 ssize_t tofill = precision - (numend - numstr);
a1d84548 472 PRINT (numstr, wnumstr, MIN (numend - numstr, precision));
b15cb495
UD
473 if (tofill > 0)
474 PADN ('0', tofill);
2f6d1f1b
UD
475 }
476
477 if (info->left && info->pad == '0' && width > 0)
478 PADN ('0', width);
479
263456bd
UD
480 if ('P' - 'A' == 'p' - 'a')
481 outchar (info->spec + ('p' - 'a'));
482 else
483 outchar (info->spec == 'A' ? 'P' : 'p');
2f6d1f1b
UD
484
485 outchar (expnegative ? '-' : '+');
486
a1d84548 487 PRINT (expstr, wexpstr, (expbuf + sizeof expbuf) - expstr);
2f6d1f1b
UD
488
489 if (info->left && info->pad != '0' && width > 0)
490 PADN (info->pad, width);
491
492 return done;
493}