1 /* GCC Quad-Precision Math Library
2 Copyright (C) 2011 Free Software Foundation, Inc.
3 Written by Jakub Jelinek <jakub@redhat.com>
5 This file is part of the libquadmath library.
6 Libquadmath is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
11 Libquadmath 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 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with libquadmath; see the file COPYING.LIB. If
18 not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19 Boston, MA 02110-1301, USA. */
25 #include "quadmath-printf.h"
27 /* Read a simple integer from a string and update the string pointer.
28 It is assumed that the first character is a digit. */
30 read_int (const char **pstr
)
32 unsigned int retval
= (unsigned char) **pstr
- '0';
34 while (isdigit ((unsigned char) *++(*pstr
)))
37 retval
+= (unsigned char) **pstr
- '0';
44 static char const blanks
[PADSIZE
] =
45 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
46 static char const zeroes
[PADSIZE
] =
47 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
48 static wchar_t const wblanks
[PADSIZE
] =
50 L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '),
51 L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' ')
53 static wchar_t const wzeroes
[PADSIZE
] =
55 L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'),
56 L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0')
59 attribute_hidden
size_t
60 __quadmath_do_pad (struct __quadmath_printf_file
*fp
, int wide
, int c
,
65 wchar_t wpadbuf
[PADSIZE
];
67 size_t w
, written
= 0;
71 padstr
= (const char *) wblanks
;
73 padstr
= (const char *) wzeroes
;
76 padstr
= (const char *) wpadbuf
;
77 for (i
= 0; i
< PADSIZE
; i
++)
89 padstr
= (const char *) padbuf
;
90 for (i
= 0; i
< PADSIZE
; i
++)
94 for (i
= n
; i
>= PADSIZE
; i
-= PADSIZE
)
96 w
= PUT (fp
, (char *) padstr
, PADSIZE
);
103 w
= PUT (fp
, (char *) padstr
, i
);
109 /* This is a stripped down version of snprintf, which just handles
110 a single %eEfFgGaA format entry with Q modifier. % has to be
111 the first character of the format string, no $ can be used. */
113 quadmath_snprintf (char *str
, size_t size
, const char *format
, ...)
115 struct printf_info info
;
117 __float128 fpnum
, *fpnum_addr
= &fpnum
, **fpnum_addr2
= &fpnum_addr
;
118 struct __quadmath_printf_file qfp
;
120 if (*format
++ != '%')
123 /* Clear information structure. */
124 memset (&info
, '\0', sizeof info
);
135 /* Check for spec modifiers. */
141 /* Output a space in place of a sign, when there is no sign. */
145 /* Always output + or - for numbers. */
149 /* Left-justify things. */
153 /* Use the "alternate form":
154 Hex has 0x or 0X, FP always has a decimal point. */
162 /* Show grouping in numbers if the locale information
167 /* Use the internationalized form of the output. Currently
168 means to use the `outdigits' of the current locale. */
181 va_start (ap
, format
);
183 /* Get the field width. */
184 /* info.width = 0; */
187 /* The field width is given in an argument.
188 A negative field width indicates left justification. */
190 info
.width
= va_arg (ap
, int);
192 else if (isdigit (*format
))
193 /* Constant width specification. */
194 info
.width
= read_int (&format
);
196 /* Get the precision. */
197 /* -1 means none given; 0 means explicit 0. */
204 /* The precision is given in an argument. */
207 info
.prec
= va_arg (ap
, int);
209 else if (isdigit (*format
))
210 info
.prec
= read_int (&format
);
212 /* "%.?" is treated like "%.0?". */
216 /* Check for type modifiers. */
217 /* info.is_long_double = 0;
223 /* We require Q modifier. */
224 if (*format
++ != 'Q')
230 /* Get the format specification. */
231 info
.spec
= (wchar_t) *format
++;
232 if (info
.spec
== L_('\0') || *format
!= '\0')
254 fpnum
= va_arg (ap
, __float128
);
259 qfp
.size
= size
? size
- 1 : 0;
263 if (info
.spec
== L_('a') || info
.spec
== L_('A'))
264 __quadmath_printf_fphex (&qfp
, &info
, (const void *const *)&fpnum_addr2
);
266 __quadmath_printf_fp (&qfp
, &info
, (const void *const *)&fpnum_addr2
);
274 #ifdef HAVE_PRINTF_HOOKS
275 static int pa_flt128
;
276 int mod_Q attribute_hidden
;
279 flt128_va (void *mem
, va_list *ap
)
281 __float128 d
= va_arg (*ap
, __float128
);
282 memcpy (mem
, &d
, sizeof (d
));
286 flt128_ais (const struct printf_info
*info
, size_t n
__attribute__ ((unused
)),
287 int *argtype
, int *size
)
289 if (info
->user
& mod_Q
)
291 argtype
[0] = pa_flt128
;
292 size
[0] = sizeof (__float128
);
295 #if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 13)
296 /* Workaround bug in glibc printf hook handling. */
306 #if __LONG_MAX__ != __LONG_LONG_MAX__
307 if (info
->is_long_double
)
308 argtype
[0] = PA_INT
|PA_FLAG_LONG_LONG
;
312 argtype
[0] = PA_INT
|PA_FLAG_LONG
;
313 else if (info
->is_short
)
314 argtype
[0] = PA_INT
|PA_FLAG_SHORT
;
315 else if (info
->is_char
)
316 argtype
[0] = PA_CHAR
;
328 if (info
->is_long_double
)
329 argtype
[0] = PA_DOUBLE
|PA_FLAG_LONG_DOUBLE
;
331 argtype
[0] = PA_DOUBLE
;
334 argtype
[0] = PA_CHAR
;
337 argtype
[0] = PA_WCHAR
;
340 argtype
[0] = PA_STRING
;
343 argtype
[0] = PA_WSTRING
;
346 argtype
[0] = PA_POINTER
;
349 argtype
[0] = PA_INT
|PA_FLAG_PTR
;
354 /* An unknown spec will consume no args. */
362 flt128_printf_fp (FILE *fp
, const struct printf_info
*info
,
363 const void *const *args
)
365 struct __quadmath_printf_file qpf
366 = { .fp
= fp
, .str
= NULL
, .size
= 0, .len
= 0, .file_p
= 1 };
368 if ((info
->user
& mod_Q
) == 0)
371 return __quadmath_printf_fp (&qpf
, info
, args
);
375 flt128_printf_fphex (FILE *fp
, const struct printf_info
*info
,
376 const void *const *args
)
378 struct __quadmath_printf_file qpf
379 = { .fp
= fp
, .str
= NULL
, .size
= 0, .len
= 0, .file_p
= 1 };
381 if ((info
->user
& mod_Q
) == 0)
384 return __quadmath_printf_fphex (&qpf
, info
, args
);
387 __attribute__((constructor
)) static void
388 register_printf_flt128 (void)
390 pa_flt128
= register_printf_type (flt128_va
);
393 mod_Q
= register_printf_modifier (L_("Q"));
396 register_printf_specifier ('f', flt128_printf_fp
, flt128_ais
);
397 register_printf_specifier ('F', flt128_printf_fp
, flt128_ais
);
398 register_printf_specifier ('e', flt128_printf_fp
, flt128_ais
);
399 register_printf_specifier ('E', flt128_printf_fp
, flt128_ais
);
400 register_printf_specifier ('g', flt128_printf_fp
, flt128_ais
);
401 register_printf_specifier ('G', flt128_printf_fp
, flt128_ais
);
402 register_printf_specifier ('a', flt128_printf_fphex
, flt128_ais
);
403 register_printf_specifier ('A', flt128_printf_fphex
, flt128_ais
);
406 __attribute__((destructor
)) static void
407 unregister_printf_flt128 (void)
409 /* No way to unregister printf type and modifier currently,
410 and only one printf specifier can be registered right now. */
411 if (pa_flt128
== -1 || mod_Q
== -1)
413 register_printf_specifier ('f', NULL
, NULL
);
414 register_printf_specifier ('F', NULL
, NULL
);
415 register_printf_specifier ('e', NULL
, NULL
);
416 register_printf_specifier ('E', NULL
, NULL
);
417 register_printf_specifier ('g', NULL
, NULL
);
418 register_printf_specifier ('G', NULL
, NULL
);
419 register_printf_specifier ('a', NULL
, NULL
);
420 register_printf_specifier ('A', NULL
, NULL
);