Home | History | Annotate | Line # | Download | only in printf
      1  1.1  mrg /* GCC Quad-Precision Math Library
      2  1.1  mrg    Copyright (C) 2011 Free Software Foundation, Inc.
      3  1.1  mrg    Written by Jakub Jelinek  <jakub (at) redhat.com>
      4  1.1  mrg 
      5  1.1  mrg This file is part of the libquadmath library.
      6  1.1  mrg Libquadmath is free software; you can redistribute it and/or
      7  1.1  mrg modify it under the terms of the GNU Library General Public
      8  1.1  mrg License as published by the Free Software Foundation; either
      9  1.1  mrg version 2 of the License, or (at your option) any later version.
     10  1.1  mrg 
     11  1.1  mrg Libquadmath is distributed in the hope that it will be useful,
     12  1.1  mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  1.1  mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  1.1  mrg Library General Public License for more details.
     15  1.1  mrg 
     16  1.1  mrg You should have received a copy of the GNU Library General Public
     17  1.1  mrg License along with libquadmath; see the file COPYING.LIB.  If
     18  1.1  mrg not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
     19  1.1  mrg Boston, MA 02110-1301, USA.  */
     20  1.1  mrg 
     21  1.1  mrg #include <config.h>
     22  1.1  mrg #include <stdarg.h>
     23  1.1  mrg #include <string.h>
     24  1.1  mrg #include <stdio.h>
     25  1.1  mrg #include "quadmath-printf.h"
     26  1.1  mrg 
     27  1.1  mrg /* Read a simple integer from a string and update the string pointer.
     28  1.1  mrg    It is assumed that the first character is a digit.  */
     29  1.1  mrg static unsigned int
     30  1.1  mrg read_int (const char **pstr)
     31  1.1  mrg {
     32  1.1  mrg   unsigned int retval = (unsigned char) **pstr - '0';
     33  1.1  mrg 
     34  1.1  mrg   while (isdigit ((unsigned char) *++(*pstr)))
     35  1.1  mrg     {
     36  1.1  mrg       retval *= 10;
     37  1.1  mrg       retval += (unsigned char) **pstr - '0';
     38  1.1  mrg     }
     39  1.1  mrg 
     40  1.1  mrg   return retval;
     41  1.1  mrg }
     42  1.1  mrg 
     43  1.1  mrg #define PADSIZE 16
     44  1.1  mrg static char const blanks[PADSIZE] =
     45  1.1  mrg {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
     46  1.1  mrg static char const zeroes[PADSIZE] =
     47  1.1  mrg {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
     48  1.1  mrg static wchar_t const wblanks[PADSIZE] =
     49  1.1  mrg {
     50  1.1  mrg   L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '),
     51  1.1  mrg   L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' ')
     52  1.1  mrg };
     53  1.1  mrg static wchar_t const wzeroes[PADSIZE] =
     54  1.1  mrg {
     55  1.1  mrg   L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'),
     56  1.1  mrg   L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0')
     57  1.1  mrg };
     58  1.1  mrg 
     59  1.1  mrg attribute_hidden size_t
     60  1.1  mrg __quadmath_do_pad (struct __quadmath_printf_file *fp, int wide, int c,
     61  1.1  mrg 		   size_t n)
     62  1.1  mrg {
     63  1.1  mrg   ssize_t i;
     64  1.1  mrg   char padbuf[PADSIZE];
     65  1.1  mrg   wchar_t wpadbuf[PADSIZE];
     66  1.1  mrg   const char *padstr;
     67  1.1  mrg   size_t w, written = 0;
     68  1.1  mrg   if (wide)
     69  1.1  mrg     {
     70  1.1  mrg       if (c == ' ')
     71  1.1  mrg 	padstr = (const char *) wblanks;
     72  1.1  mrg       else if (c == '0')
     73  1.1  mrg 	padstr = (const char *) wzeroes;
     74  1.1  mrg       else
     75  1.1  mrg 	{
     76  1.1  mrg 	  padstr = (const char *) wpadbuf;
     77  1.1  mrg 	  for (i = 0; i < PADSIZE; i++)
     78  1.1  mrg 	    wpadbuf[i] = c;
     79  1.1  mrg 	}
     80  1.1  mrg     }
     81  1.1  mrg   else
     82  1.1  mrg     {
     83  1.1  mrg       if (c == ' ')
     84  1.1  mrg 	padstr = blanks;
     85  1.1  mrg       else if (c == '0')
     86  1.1  mrg 	padstr = zeroes;
     87  1.1  mrg       else
     88  1.1  mrg 	{
     89  1.1  mrg 	  padstr = (const char *) padbuf;
     90  1.1  mrg 	  for (i = 0; i < PADSIZE; i++)
     91  1.1  mrg 	    padbuf[i] = c;
     92  1.1  mrg 	}
     93  1.1  mrg     }
     94  1.1  mrg   for (i = n; i >= PADSIZE; i -= PADSIZE)
     95  1.1  mrg     {
     96  1.1  mrg       w = PUT (fp, (char *) padstr, PADSIZE);
     97  1.1  mrg       written += w;
     98  1.1  mrg       if (w != PADSIZE)
     99  1.1  mrg 	return written;
    100  1.1  mrg     }
    101  1.1  mrg   if (i > 0)
    102  1.1  mrg     {
    103  1.1  mrg       w = PUT (fp, (char *) padstr, i);
    104  1.1  mrg       written += w;
    105  1.1  mrg     }
    106  1.1  mrg   return written;
    107  1.1  mrg }
    108  1.1  mrg 
    109  1.1  mrg /* This is a stripped down version of snprintf, which just handles
    110  1.1  mrg    a single %eEfFgGaA format entry with Q modifier.  % has to be
    111  1.1  mrg    the first character of the format string, no $ can be used.  */
    112  1.1  mrg int
    113  1.1  mrg quadmath_snprintf (char *str, size_t size, const char *format, ...)
    114  1.1  mrg {
    115  1.1  mrg   struct printf_info info;
    116  1.1  mrg   va_list ap;
    117  1.1  mrg   __float128 fpnum, *fpnum_addr = &fpnum, **fpnum_addr2 = &fpnum_addr;
    118  1.1  mrg   struct __quadmath_printf_file qfp;
    119  1.1  mrg 
    120  1.1  mrg   if (*format++ != '%')
    121  1.1  mrg     return -1;
    122  1.1  mrg 
    123  1.1  mrg   /* Clear information structure.  */
    124  1.1  mrg   memset (&info, '\0', sizeof info);
    125  1.1  mrg   /* info.alt = 0;
    126  1.1  mrg   info.space = 0;
    127  1.1  mrg   info.left = 0;
    128  1.1  mrg   info.showsign = 0;
    129  1.1  mrg   info.group = 0;
    130  1.1  mrg   info.i18n = 0;
    131  1.1  mrg   info.extra = 0; */
    132  1.1  mrg   info.pad = ' ';
    133  1.1  mrg   /* info.wide = 0; */
    134  1.1  mrg 
    135  1.1  mrg   /* Check for spec modifiers.  */
    136  1.1  mrg   do
    137  1.1  mrg     {
    138  1.1  mrg       switch (*format)
    139  1.1  mrg 	{
    140  1.1  mrg 	case ' ':
    141  1.1  mrg 	  /* Output a space in place of a sign, when there is no sign.  */
    142  1.1  mrg 	  info.space = 1;
    143  1.1  mrg 	  continue;
    144  1.1  mrg 	case '+':
    145  1.1  mrg 	  /* Always output + or - for numbers.  */
    146  1.1  mrg 	  info.showsign = 1;
    147  1.1  mrg 	  continue;
    148  1.1  mrg 	case '-':
    149  1.1  mrg 	  /* Left-justify things.  */
    150  1.1  mrg 	  info.left = 1;
    151  1.1  mrg 	  continue;
    152  1.1  mrg 	case '#':
    153  1.1  mrg 	  /* Use the "alternate form":
    154  1.1  mrg 	     Hex has 0x or 0X, FP always has a decimal point.  */
    155  1.1  mrg 	  info.alt = 1;
    156  1.1  mrg 	  continue;
    157  1.1  mrg 	case '0':
    158  1.1  mrg 	  /* Pad with 0s.  */
    159  1.1  mrg 	  info.pad = '0';
    160  1.1  mrg 	  continue;
    161  1.1  mrg 	case '\'':
    162  1.1  mrg 	  /* Show grouping in numbers if the locale information
    163  1.1  mrg 	     indicates any.  */
    164  1.1  mrg 	  info.group = 1;
    165  1.1  mrg 	  continue;
    166  1.1  mrg 	case 'I':
    167  1.1  mrg 	  /* Use the internationalized form of the output.  Currently
    168  1.1  mrg 	     means to use the `outdigits' of the current locale.  */
    169  1.1  mrg 	  info.i18n = 1;
    170  1.1  mrg 	  continue;
    171  1.1  mrg 	default:
    172  1.1  mrg 	  break;
    173  1.1  mrg 	}
    174  1.1  mrg       break;
    175  1.1  mrg     }
    176  1.1  mrg   while (*++format);
    177  1.1  mrg 
    178  1.1  mrg   if (info.left)
    179  1.1  mrg     info.pad = ' ';
    180  1.1  mrg 
    181  1.1  mrg   va_start (ap, format);
    182  1.1  mrg 
    183  1.1  mrg   /* Get the field width.  */
    184  1.1  mrg   /* info.width = 0; */
    185  1.1  mrg   if (*format == '*')
    186  1.1  mrg     {
    187  1.1  mrg       /* The field width is given in an argument.
    188  1.1  mrg 	 A negative field width indicates left justification.  */
    189  1.1  mrg       ++format;
    190  1.1  mrg       info.width = va_arg (ap, int);
    191  1.1  mrg     }
    192  1.2  mrg   else if (isdigit ((unsigned char)*format))
    193  1.1  mrg     /* Constant width specification.  */
    194  1.1  mrg     info.width = read_int (&format);
    195  1.1  mrg 
    196  1.1  mrg   /* Get the precision.  */
    197  1.1  mrg   /* -1 means none given; 0 means explicit 0.  */
    198  1.1  mrg   info.prec = -1;
    199  1.1  mrg   if (*format == '.')
    200  1.1  mrg     {
    201  1.1  mrg       ++format;
    202  1.1  mrg       if (*format == '*')
    203  1.1  mrg 	{
    204  1.1  mrg 	  /* The precision is given in an argument.  */
    205  1.1  mrg 	  ++format;
    206  1.1  mrg 
    207  1.1  mrg 	  info.prec = va_arg (ap, int);
    208  1.1  mrg 	}
    209  1.2  mrg       else if (isdigit ((unsigned char)*format))
    210  1.1  mrg 	info.prec = read_int (&format);
    211  1.1  mrg       else
    212  1.1  mrg 	/* "%.?" is treated like "%.0?".  */
    213  1.1  mrg 	info.prec = 0;
    214  1.1  mrg     }
    215  1.1  mrg 
    216  1.1  mrg   /* Check for type modifiers.  */
    217  1.1  mrg   /* info.is_long_double = 0;
    218  1.1  mrg   info.is_short = 0;
    219  1.1  mrg   info.is_long = 0;
    220  1.1  mrg   info.is_char = 0;
    221  1.1  mrg   info.user = 0; */
    222  1.1  mrg 
    223  1.1  mrg   /* We require Q modifier.  */
    224  1.1  mrg   if (*format++ != 'Q')
    225  1.1  mrg     {
    226  1.1  mrg       va_end (ap);
    227  1.1  mrg       return -1;
    228  1.1  mrg     }
    229  1.1  mrg 
    230  1.1  mrg   /* Get the format specification.  */
    231  1.1  mrg   info.spec = (wchar_t) *format++;
    232  1.1  mrg   if (info.spec == L_('\0') || *format != '\0')
    233  1.1  mrg     {
    234  1.1  mrg       va_end (ap);
    235  1.1  mrg       return -1;
    236  1.1  mrg     }
    237  1.1  mrg 
    238  1.1  mrg   switch (info.spec)
    239  1.1  mrg     {
    240  1.1  mrg     case L_('e'):
    241  1.1  mrg     case L_('E'):
    242  1.1  mrg     case L_('f'):
    243  1.1  mrg     case L_('F'):
    244  1.1  mrg     case L_('g'):
    245  1.1  mrg     case L_('G'):
    246  1.1  mrg     case L_('a'):
    247  1.1  mrg     case L_('A'):
    248  1.1  mrg       break;
    249  1.1  mrg     default:
    250  1.1  mrg       va_end (ap);
    251  1.1  mrg       return -1;
    252  1.1  mrg     }
    253  1.1  mrg 
    254  1.1  mrg   fpnum = va_arg (ap, __float128);
    255  1.1  mrg   va_end (ap);
    256  1.1  mrg 
    257  1.1  mrg   qfp.fp = NULL;
    258  1.1  mrg   qfp.str = str;
    259  1.1  mrg   qfp.size = size ? size - 1 : 0;
    260  1.1  mrg   qfp.len = 0;
    261  1.1  mrg   qfp.file_p = 0;
    262  1.1  mrg 
    263  1.1  mrg   if (info.spec == L_('a') || info.spec == L_('A'))
    264  1.1  mrg     __quadmath_printf_fphex (&qfp, &info, (const void *const *)&fpnum_addr2);
    265  1.1  mrg   else
    266  1.1  mrg     __quadmath_printf_fp (&qfp, &info, (const void *const *)&fpnum_addr2);
    267  1.1  mrg 
    268  1.1  mrg   if (size)
    269  1.1  mrg     *qfp.str = '\0';
    270  1.1  mrg 
    271  1.1  mrg   return qfp.len;
    272  1.1  mrg }
    273  1.1  mrg 
    274  1.1  mrg #ifdef HAVE_PRINTF_HOOKS
    275  1.1  mrg static int pa_flt128;
    276  1.1  mrg int mod_Q attribute_hidden;
    277  1.1  mrg 
    278  1.1  mrg static void
    279  1.1  mrg flt128_va (void *mem, va_list *ap)
    280  1.1  mrg {
    281  1.1  mrg   __float128 d = va_arg (*ap, __float128);
    282  1.1  mrg   memcpy (mem, &d, sizeof (d));
    283  1.1  mrg }
    284  1.1  mrg 
    285  1.1  mrg static int
    286  1.1  mrg flt128_ais (const struct printf_info *info, size_t n __attribute__ ((unused)),
    287  1.1  mrg 	    int *argtype, int *size)
    288  1.1  mrg {
    289  1.1  mrg   if (info->user & mod_Q)
    290  1.1  mrg     {
    291  1.1  mrg       argtype[0] = pa_flt128;
    292  1.1  mrg       size[0] = sizeof (__float128);
    293  1.1  mrg       return 1;
    294  1.1  mrg     }
    295  1.1  mrg #if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 13)
    296  1.1  mrg   /* Workaround bug in glibc printf hook handling.  */
    297  1.1  mrg   size[0] = -1;
    298  1.1  mrg   switch (info->spec)
    299  1.1  mrg     {
    300  1.1  mrg     case L_('i'):
    301  1.1  mrg     case L_('d'):
    302  1.1  mrg     case L_('u'):
    303  1.1  mrg     case L_('o'):
    304  1.1  mrg     case L_('X'):
    305  1.1  mrg     case L_('x'):
    306  1.1  mrg #if __LONG_MAX__ != __LONG_LONG_MAX__
    307  1.1  mrg       if (info->is_long_double)
    308  1.1  mrg 	argtype[0] = PA_INT|PA_FLAG_LONG_LONG;
    309  1.1  mrg       else
    310  1.1  mrg #endif
    311  1.1  mrg       if (info->is_long)
    312  1.1  mrg 	argtype[0] = PA_INT|PA_FLAG_LONG;
    313  1.1  mrg       else if (info->is_short)
    314  1.1  mrg 	argtype[0] = PA_INT|PA_FLAG_SHORT;
    315  1.1  mrg       else if (info->is_char)
    316  1.1  mrg 	argtype[0] = PA_CHAR;
    317  1.1  mrg       else
    318  1.1  mrg 	argtype[0] = PA_INT;
    319  1.1  mrg       return 1;
    320  1.1  mrg     case L_('e'):
    321  1.1  mrg     case L_('E'):
    322  1.1  mrg     case L_('f'):
    323  1.1  mrg     case L_('F'):
    324  1.1  mrg     case L_('g'):
    325  1.1  mrg     case L_('G'):
    326  1.1  mrg     case L_('a'):
    327  1.1  mrg     case L_('A'):
    328  1.1  mrg       if (info->is_long_double)
    329  1.1  mrg 	argtype[0] = PA_DOUBLE|PA_FLAG_LONG_DOUBLE;
    330  1.1  mrg       else
    331  1.1  mrg 	argtype[0] = PA_DOUBLE;
    332  1.1  mrg       return 1;
    333  1.1  mrg     case L_('c'):
    334  1.1  mrg       argtype[0] = PA_CHAR;
    335  1.1  mrg       return 1;
    336  1.1  mrg     case L_('C'):
    337  1.1  mrg       argtype[0] = PA_WCHAR;
    338  1.1  mrg       return 1;
    339  1.1  mrg     case L_('s'):
    340  1.1  mrg       argtype[0] = PA_STRING;
    341  1.1  mrg       return 1;
    342  1.1  mrg     case L_('S'):
    343  1.1  mrg       argtype[0] = PA_WSTRING;
    344  1.1  mrg       return 1;
    345  1.1  mrg     case L_('p'):
    346  1.1  mrg       argtype[0] = PA_POINTER;
    347  1.1  mrg       return 1;
    348  1.1  mrg     case L_('n'):
    349  1.1  mrg       argtype[0] = PA_INT|PA_FLAG_PTR;
    350  1.1  mrg       return 1;
    351  1.1  mrg 
    352  1.1  mrg     case L_('m'):
    353  1.1  mrg     default:
    354  1.1  mrg       /* An unknown spec will consume no args.  */
    355  1.1  mrg       return 0;
    356  1.1  mrg     }
    357  1.1  mrg #endif
    358  1.1  mrg   return -1;
    359  1.1  mrg }
    360  1.1  mrg 
    361  1.1  mrg static int
    362  1.1  mrg flt128_printf_fp (FILE *fp, const struct printf_info *info,
    363  1.1  mrg 		  const void *const *args)
    364  1.1  mrg {
    365  1.1  mrg   struct __quadmath_printf_file qpf
    366  1.1  mrg     = { .fp = fp, .str = NULL, .size = 0, .len = 0, .file_p = 1 };
    367  1.1  mrg 
    368  1.1  mrg   if ((info->user & mod_Q) == 0)
    369  1.1  mrg     return -2;
    370  1.1  mrg 
    371  1.1  mrg   return __quadmath_printf_fp (&qpf, info, args);
    372  1.1  mrg }
    373  1.1  mrg 
    374  1.1  mrg static int
    375  1.1  mrg flt128_printf_fphex (FILE *fp, const struct printf_info *info,
    376  1.1  mrg 		     const void *const *args)
    377  1.1  mrg {
    378  1.1  mrg   struct __quadmath_printf_file qpf
    379  1.1  mrg     = { .fp = fp, .str = NULL, .size = 0, .len = 0, .file_p = 1 };
    380  1.1  mrg 
    381  1.1  mrg   if ((info->user & mod_Q) == 0)
    382  1.1  mrg     return -2;
    383  1.1  mrg 
    384  1.1  mrg   return __quadmath_printf_fphex (&qpf, info, args);
    385  1.1  mrg }
    386  1.1  mrg 
    387  1.1  mrg __attribute__((constructor)) static void
    388  1.1  mrg register_printf_flt128 (void)
    389  1.1  mrg {
    390  1.1  mrg   pa_flt128 = register_printf_type (flt128_va);
    391  1.1  mrg   if (pa_flt128 == -1)
    392  1.1  mrg     return;
    393  1.1  mrg   mod_Q = register_printf_modifier (L_("Q"));
    394  1.1  mrg   if (mod_Q == -1)
    395  1.1  mrg     return;
    396  1.1  mrg   register_printf_specifier ('f', flt128_printf_fp, flt128_ais);
    397  1.1  mrg   register_printf_specifier ('F', flt128_printf_fp, flt128_ais);
    398  1.1  mrg   register_printf_specifier ('e', flt128_printf_fp, flt128_ais);
    399  1.1  mrg   register_printf_specifier ('E', flt128_printf_fp, flt128_ais);
    400  1.1  mrg   register_printf_specifier ('g', flt128_printf_fp, flt128_ais);
    401  1.1  mrg   register_printf_specifier ('G', flt128_printf_fp, flt128_ais);
    402  1.1  mrg   register_printf_specifier ('a', flt128_printf_fphex, flt128_ais);
    403  1.1  mrg   register_printf_specifier ('A', flt128_printf_fphex, flt128_ais);
    404  1.1  mrg }
    405  1.1  mrg 
    406  1.1  mrg __attribute__((destructor)) static void
    407  1.1  mrg unregister_printf_flt128 (void)
    408  1.1  mrg {
    409  1.1  mrg   /* No way to unregister printf type and modifier currently,
    410  1.1  mrg      and only one printf specifier can be registered right now.  */
    411  1.1  mrg   if (pa_flt128 == -1 || mod_Q == -1)
    412  1.1  mrg     return;
    413  1.1  mrg   register_printf_specifier ('f', NULL, NULL);
    414  1.1  mrg   register_printf_specifier ('F', NULL, NULL);
    415  1.1  mrg   register_printf_specifier ('e', NULL, NULL);
    416  1.1  mrg   register_printf_specifier ('E', NULL, NULL);
    417  1.1  mrg   register_printf_specifier ('g', NULL, NULL);
    418  1.1  mrg   register_printf_specifier ('G', NULL, NULL);
    419  1.1  mrg   register_printf_specifier ('a', NULL, NULL);
    420  1.1  mrg   register_printf_specifier ('A', NULL, NULL);
    421  1.1  mrg }
    422  1.1  mrg #endif
    423