]> git.ipfire.org Git - thirdparty/glibc.git/blame - stdio-common/printf_fphex.c
update from main archive 970304
[thirdparty/glibc.git] / stdio-common / printf_fphex.c
CommitLineData
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)
49ssize_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
82int
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