Wolfgang Thalleradd gcc 4.70aaf905c14 years agoHistory
422 lines · 10.1 KB · C
RawDownload
/* GCC Quad-Precision Math Library   Copyright (C) 2011 Free Software Foundation, Inc.   Written by Jakub Jelinek  <jakub@redhat.com> This file is part of the libquadmath library.Libquadmath is free software; you can redistribute it and/ormodify it under the terms of the GNU Library General PublicLicense as published by the Free Software Foundation; eitherversion 2 of the License, or (at your option) any later version. Libquadmath is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNULibrary General Public License for more details. You should have received a copy of the GNU Library General PublicLicense along with libquadmath; see the file COPYING.LIB.  Ifnot, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,Boston, MA 02110-1301, USA.  */ #include <config.h>#include <stdarg.h>#include <string.h>#include <stdio.h>#include "quadmath-printf.h" /* Read a simple integer from a string and update the string pointer.   It is assumed that the first character is a digit.  */static unsigned intread_int (const char **pstr){  unsigned int retval = (unsigned char) **pstr - '0';   while (isdigit ((unsigned char) *++(*pstr)))    {      retval *= 10;      retval += (unsigned char) **pstr - '0';    }   return retval;} #define PADSIZE 16static char const blanks[PADSIZE] ={' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};static char const zeroes[PADSIZE] ={'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};static wchar_t const wblanks[PADSIZE] ={  L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '),  L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' ')};static wchar_t const wzeroes[PADSIZE] ={  L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'),  L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0')}; attribute_hidden size_t__quadmath_do_pad (struct __quadmath_printf_file *fp, int wide, int c,		   size_t n){  ssize_t i;  char padbuf[PADSIZE];  wchar_t wpadbuf[PADSIZE];  const char *padstr;  size_t w, written = 0;  if (wide)    {      if (c == ' ')	padstr = (const char *) wblanks;      else if (c == '0')	padstr = (const char *) wzeroes;      else	{	  padstr = (const char *) wpadbuf;	  for (i = 0; i < PADSIZE; i++)	    wpadbuf[i] = c;	}    }  else    {      if (c == ' ')	padstr = blanks;      else if (c == '0')	padstr = zeroes;      else	{	  padstr = (const char *) padbuf;	  for (i = 0; i < PADSIZE; i++)	    padbuf[i] = c;	}    }  for (i = n; i >= PADSIZE; i -= PADSIZE)    {      w = PUT (fp, (char *) padstr, PADSIZE);      written += w;      if (w != PADSIZE)	return written;    }  if (i > 0)    {      w = PUT (fp, (char *) padstr, i);      written += w;    }  return written;} /* This is a stripped down version of snprintf, which just handles   a single %eEfFgGaA format entry with Q modifier.  % has to be   the first character of the format string, no $ can be used.  */intquadmath_snprintf (char *str, size_t size, const char *format, ...){  struct printf_info info;  va_list ap;  __float128 fpnum, *fpnum_addr = &fpnum, **fpnum_addr2 = &fpnum_addr;  struct __quadmath_printf_file qfp;   if (*format++ != '%')    return -1;   /* Clear information structure.  */  memset (&info, '\0', sizeof info);  /* info.alt = 0;  info.space = 0;  info.left = 0;  info.showsign = 0;  info.group = 0;  info.i18n = 0;  info.extra = 0; */  info.pad = ' ';  /* info.wide = 0; */   /* Check for spec modifiers.  */  do    {      switch (*format)	{	case ' ':	  /* Output a space in place of a sign, when there is no sign.  */	  info.space = 1;	  continue;	case '+':	  /* Always output + or - for numbers.  */	  info.showsign = 1;	  continue;	case '-':	  /* Left-justify things.  */	  info.left = 1;	  continue;	case '#':	  /* Use the "alternate form":	     Hex has 0x or 0X, FP always has a decimal point.  */	  info.alt = 1;	  continue;	case '0':	  /* Pad with 0s.  */	  info.pad = '0';	  continue;	case '\'':	  /* Show grouping in numbers if the locale information	     indicates any.  */	  info.group = 1;	  continue;	case 'I':	  /* Use the internationalized form of the output.  Currently	     means to use the `outdigits' of the current locale.  */	  info.i18n = 1;	  continue;	default:	  break;	}      break;    }  while (*++format);   if (info.left)    info.pad = ' ';   va_start (ap, format);   /* Get the field width.  */  /* info.width = 0; */  if (*format == '*')    {      /* The field width is given in an argument.	 A negative field width indicates left justification.  */      ++format;      info.width = va_arg (ap, int);    }  else if (isdigit (*format))    /* Constant width specification.  */    info.width = read_int (&format);   /* Get the precision.  */  /* -1 means none given; 0 means explicit 0.  */  info.prec = -1;  if (*format == '.')    {      ++format;      if (*format == '*')	{	  /* The precision is given in an argument.  */	  ++format; 	  info.prec = va_arg (ap, int);	}      else if (isdigit (*format))	info.prec = read_int (&format);      else	/* "%.?" is treated like "%.0?".  */	info.prec = 0;    }   /* Check for type modifiers.  */  /* info.is_long_double = 0;  info.is_short = 0;  info.is_long = 0;  info.is_char = 0;  info.user = 0; */   /* We require Q modifier.  */  if (*format++ != 'Q')    {      va_end (ap);      return -1;    }   /* Get the format specification.  */  info.spec = (wchar_t) *format++;  if (info.spec == L_('\0') || *format != '\0')    {      va_end (ap);      return -1;    }   switch (info.spec)    {    case L_('e'):    case L_('E'):    case L_('f'):    case L_('F'):    case L_('g'):    case L_('G'):    case L_('a'):    case L_('A'):      break;    default:      va_end (ap);      return -1;    }   fpnum = va_arg (ap, __float128);  va_end (ap);   qfp.fp = NULL;  qfp.str = str;  qfp.size = size ? size - 1 : 0;  qfp.len = 0;  qfp.file_p = 0;   if (info.spec == L_('a') || info.spec == L_('A'))    __quadmath_printf_fphex (&qfp, &info, (const void *const *)&fpnum_addr2);  else    __quadmath_printf_fp (&qfp, &info, (const void *const *)&fpnum_addr2);   if (size)    *qfp.str = '\0';   return qfp.len;} #ifdef HAVE_PRINTF_HOOKSstatic int pa_flt128;int mod_Q attribute_hidden; static voidflt128_va (void *mem, va_list *ap){   __float128 d = va_arg (*ap, __float128);  memcpy (mem, &d, sizeof (d));} static intflt128_ais (const struct printf_info *info, size_t n __attribute__ ((unused)),	    int *argtype, int *size){  if (info->user & mod_Q)    {      argtype[0] = pa_flt128;      size[0] = sizeof (__float128);      return 1;    }#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 13)  /* Workaround bug in glibc printf hook handling.  */  size[0] = -1;  switch (info->spec)    {    case L_('i'):    case L_('d'):    case L_('u'):    case L_('o'):    case L_('X'):    case L_('x'):#if __LONG_MAX__ != __LONG_LONG_MAX__      if (info->is_long_double)	argtype[0] = PA_INT|PA_FLAG_LONG_LONG;      else#endif      if (info->is_long)	argtype[0] = PA_INT|PA_FLAG_LONG;      else if (info->is_short)	argtype[0] = PA_INT|PA_FLAG_SHORT;      else if (info->is_char)	argtype[0] = PA_CHAR;      else	argtype[0] = PA_INT;      return 1;    case L_('e'):    case L_('E'):    case L_('f'):    case L_('F'):    case L_('g'):    case L_('G'):    case L_('a'):    case L_('A'):      if (info->is_long_double)	argtype[0] = PA_DOUBLE|PA_FLAG_LONG_DOUBLE;      else	argtype[0] = PA_DOUBLE;      return 1;    case L_('c'):      argtype[0] = PA_CHAR;      return 1;    case L_('C'):      argtype[0] = PA_WCHAR;      return 1;    case L_('s'):      argtype[0] = PA_STRING;      return 1;    case L_('S'):      argtype[0] = PA_WSTRING;      return 1;    case L_('p'):      argtype[0] = PA_POINTER;      return 1;    case L_('n'):      argtype[0] = PA_INT|PA_FLAG_PTR;      return 1;     case L_('m'):    default:      /* An unknown spec will consume no args.  */      return 0;    }#endif  return -1;} static intflt128_printf_fp (FILE *fp, const struct printf_info *info,		  const void *const *args){  struct __quadmath_printf_file qpf    = { .fp = fp, .str = NULL, .size = 0, .len = 0, .file_p = 1 };   if ((info->user & mod_Q) == 0)    return -2;   return __quadmath_printf_fp (&qpf, info, args);} static intflt128_printf_fphex (FILE *fp, const struct printf_info *info,		     const void *const *args){  struct __quadmath_printf_file qpf    = { .fp = fp, .str = NULL, .size = 0, .len = 0, .file_p = 1 };   if ((info->user & mod_Q) == 0)    return -2;   return __quadmath_printf_fphex (&qpf, info, args);} __attribute__((constructor)) static voidregister_printf_flt128 (void){  pa_flt128 = register_printf_type (flt128_va);  if (pa_flt128 == -1)    return;  mod_Q = register_printf_modifier (L_("Q"));  if (mod_Q == -1)    return;  register_printf_specifier ('f', flt128_printf_fp, flt128_ais);  register_printf_specifier ('F', flt128_printf_fp, flt128_ais);  register_printf_specifier ('e', flt128_printf_fp, flt128_ais);  register_printf_specifier ('E', flt128_printf_fp, flt128_ais);  register_printf_specifier ('g', flt128_printf_fp, flt128_ais);  register_printf_specifier ('G', flt128_printf_fp, flt128_ais);  register_printf_specifier ('a', flt128_printf_fphex, flt128_ais);  register_printf_specifier ('A', flt128_printf_fphex, flt128_ais);} __attribute__((destructor)) static voidunregister_printf_flt128 (void){  /* No way to unregister printf type and modifier currently,     and only one printf specifier can be registered right now.  */  if (pa_flt128 == -1 || mod_Q == -1)    return;  register_printf_specifier ('f', NULL, NULL);  register_printf_specifier ('F', NULL, NULL);  register_printf_specifier ('e', NULL, NULL);  register_printf_specifier ('E', NULL, NULL);  register_printf_specifier ('g', NULL, NULL);  register_printf_specifier ('G', NULL, NULL);  register_printf_specifier ('a', NULL, NULL);  register_printf_specifier ('A', NULL, NULL);}#endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t