1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1985-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* David Korn <dgk@research.att.com> *
1N/A* Phong Vo <kpv@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#if __STDC__
1N/A#include "FEATURE/isoc99"
1N/A#endif
1N/A#include "sfhdr.h"
1N/A
1N/A/* Convert a floating point value to ASCII.
1N/A**
1N/A** Written by Kiem-Phong Vo and Glenn Fowler (SFFMT_AFORMAT)
1N/A*/
1N/A
1N/Astatic char *lc_inf = "inf", *uc_inf = "INF";
1N/Astatic char *lc_nan = "nan", *uc_nan = "NAN";
1N/Astatic char *Zero = "0";
1N/A#define SF_INF ((_Sfi = 3), strlcpy(buf, (format & SFFMT_UPPER) ? uc_inf : lc_inf, size), buf)
1N/A#define SF_NAN ((_Sfi = 3), strlcpy(buf, (format & SFFMT_UPPER) ? uc_nan : lc_nan, size), buf)
1N/A#define SF_ZERO ((_Sfi = 1), strlcpy(buf, Zero, size), buf)
1N/A#define SF_INTPART (SF_IDIGITS/2)
1N/A
1N/A#if ! _lib_isnan
1N/A#if _lib_fpclassify
1N/A#define isnan(n) (fpclassify(n)==FP_NAN)
1N/A#define isnanl(n) (fpclassify(n)==FP_NAN)
1N/A#else
1N/A#define isnan(n) (memcmp((void*)&n,(void*)&_Sfdnan,sizeof(n))==0)
1N/A#define isnanl(n) (memcmp((void*)&n,(void*)&_Sflnan,sizeof(n))==0)
1N/A#endif
1N/A#else
1N/A#if ! _lib_isnanl
1N/A#define isnanl(n) isnan(n)
1N/A#endif
1N/A#endif
1N/A
1N/A#if ! _lib_signbit && defined(signbit)
1N/A#undef _lib_signbit
1N/A#define _lib_signbit 1
1N/A#endif
1N/A
1N/A#if ! _lib_signbit
1N/A#if ! _ast_fltmax_double
1N/Astatic int neg0ld(Sfdouble_t f)
1N/A{
1N/A Sfdouble_t z = -0.0;
1N/A return !memcmp(&f, &z, sizeof(f));
1N/A}
1N/A#endif
1N/Astatic int neg0d(double f)
1N/A{
1N/A double z = -0.0;
1N/A return !memcmp(&f, &z, sizeof(f));
1N/A}
1N/A#endif
1N/A
1N/A#if ULONG_DIG && ULONG_DIG < (DBL_DIG-1)
1N/A#define CVT_LDBL_INT long
1N/A#define CVT_LDBL_MAXINT LONG_MAX
1N/A#else
1N/A#if UINT_DIG && UINT_DIG < (DBL_DIG-1)
1N/A#define CVT_LDBL_INT int
1N/A#define CVT_LDBL_MAXINT INT_MAX
1N/A#else
1N/A#define CVT_LDBL_INT long
1N/A#define CVT_LDBL_MAXINT SF_MAXLONG
1N/A#endif
1N/A#endif
1N/A
1N/A#if ULONG_DIG && ULONG_DIG < (DBL_DIG-1)
1N/A#define CVT_DBL_INT long
1N/A#define CVT_DBL_MAXINT LONG_MAX
1N/A#else
1N/A#if UINT_DIG && UINT_DIG < (DBL_DIG-1)
1N/A#define CVT_DBL_INT int
1N/A#define CVT_DBL_MAXINT INT_MAX
1N/A#else
1N/A#define CVT_DBL_INT long
1N/A#define CVT_DBL_MAXINT SF_MAXLONG
1N/A#endif
1N/A#endif
1N/A
1N/A#if __STD_C
1N/Achar* _sfcvt(Void_t* vp, char* buf, size_t size, int n_digit,
1N/A int* decpt, int* sign, int* len, int format)
1N/A#else
1N/Achar* _sfcvt(vp,buf,size,n_digit,decpt,sign,len,format)
1N/AVoid_t* vp; /* pointer to value to convert */
1N/Achar* buf; /* conversion goes here */
1N/Asize_t size; /* size of buf */
1N/Aint n_digit; /* number of digits wanted */
1N/Aint* decpt; /* to return decimal point */
1N/Aint* sign; /* to return sign */
1N/Aint* len; /* return string length */
1N/Aint format; /* conversion format */
1N/A#endif
1N/A{
1N/A reg char *sp;
1N/A reg long n, v;
1N/A reg char *ep, *b, *endsp, *t;
1N/A int x;
1N/A _ast_flt_unsigned_max_t m;
1N/A
1N/A static char lx[] = "0123456789abcdef";
1N/A static char ux[] = "0123456789ABCDEF";
1N/A
1N/A *sign = *decpt = 0;
1N/A
1N/A#if !_ast_fltmax_double
1N/A if(format&SFFMT_LDOUBLE)
1N/A { Sfdouble_t f = *(Sfdouble_t*)vp;
1N/A
1N/A if(isnanl(f))
1N/A {
1N/A#if _lib_signbit
1N/A if (signbit(f))
1N/A#else
1N/A if (f < 0)
1N/A#endif
1N/A *sign = 1;
1N/A return SF_NAN;
1N/A }
1N/A#if _lib_isinf
1N/A if (n = isinf(f))
1N/A {
1N/A#if _lib_signbit
1N/A if (signbit(f))
1N/A#else
1N/A if (n < 0 || f < 0)
1N/A#endif
1N/A *sign = 1;
1N/A return SF_INF;
1N/A }
1N/A#endif
1N/A# if _c99_in_the_wild
1N/A# if _lib_signbit
1N/A if (signbit(f))
1N/A# else
1N/A# if _lib_copysignl
1N/A if (copysignl(1.0, f) < 0.0)
1N/A# else
1N/A# if _lib_copysign
1N/A if (copysign(1.0, (double)f) < 0.0)
1N/A# else
1N/A if (f < 0.0)
1N/A# endif
1N/A# endif
1N/A# endif
1N/A { f = -f;
1N/A *sign = 1;
1N/A }
1N/A# if _lib_fpclassify
1N/A switch (fpclassify(f))
1N/A {
1N/A case FP_INFINITE:
1N/A return SF_INF;
1N/A case FP_NAN:
1N/A return SF_NAN;
1N/A case FP_ZERO:
1N/A return SF_ZERO;
1N/A }
1N/A# endif
1N/A# else
1N/A# if _lib_signbit
1N/A if (signbit(f))
1N/A# else
1N/A if (f < 0.0 || f == 0.0 && neg0ld(f))
1N/A# endif
1N/A { f = -f;
1N/A *sign = 1;
1N/A }
1N/A# endif
1N/A if(f < LDBL_MIN)
1N/A return SF_ZERO;
1N/A if(f > LDBL_MAX)
1N/A return SF_INF;
1N/A
1N/A if(format & SFFMT_AFORMAT)
1N/A { Sfdouble_t g;
1N/A b = sp = buf;
1N/A ep = (format & SFFMT_UPPER) ? ux : lx;
1N/A if(n_digit <= 0 || n_digit >= (size - 9))
1N/A n_digit = size - 9;
1N/A endsp = sp + n_digit + 1;
1N/A
1N/A g = frexpl(f, &x);
1N/A *decpt = x;
1N/A f = ldexpl(g, 8 * sizeof(m) - 3);
1N/A
1N/A for (;;)
1N/A { m = f;
1N/A x = 8 * sizeof(m);
1N/A while ((x -= 4) >= 0)
1N/A { *sp++ = ep[(m >> x) & 0xf];
1N/A if (sp >= endsp)
1N/A goto around;
1N/A }
1N/A f -= m;
1N/A f = ldexpl(f, 8 * sizeof(m));
1N/A }
1N/A }
1N/A
1N/A n = 0;
1N/A if(f >= (Sfdouble_t)CVT_LDBL_MAXINT)
1N/A { /* scale to a small enough number to fit an int */
1N/A v = SF_MAXEXP10-1;
1N/A do
1N/A { if(f < _Sfpos10[v])
1N/A v -= 1;
1N/A else
1N/A {
1N/A f *= _Sfneg10[v];
1N/A if((n += (1<<v)) >= SF_IDIGITS)
1N/A return SF_INF;
1N/A }
1N/A } while(f >= (Sfdouble_t)CVT_LDBL_MAXINT);
1N/A }
1N/A else if(f > 0.0 && f < 0.1)
1N/A { /* scale to avoid excessive multiply by 10 below */
1N/A v = SF_MAXEXP10-1;
1N/A do
1N/A { if(f <= _Sfneg10[v])
1N/A { f *= _Sfpos10[v];
1N/A if((n += (1<<v)) >= SF_IDIGITS)
1N/A return SF_INF;
1N/A }
1N/A else if (--v < 0)
1N/A break;
1N/A } while(f < 0.1);
1N/A n = -n;
1N/A }
1N/A *decpt = (int)n;
1N/A
1N/A b = sp = buf + SF_INTPART;
1N/A if((v = (CVT_LDBL_INT)f) != 0)
1N/A { /* translate the integer part */
1N/A f -= (Sfdouble_t)v;
1N/A
1N/A sfucvt(v,sp,n,ep,CVT_LDBL_INT,unsigned CVT_LDBL_INT);
1N/A
1N/A n = b-sp;
1N/A if((*decpt += (int)n) >= SF_IDIGITS)
1N/A return SF_INF;
1N/A b = sp;
1N/A sp = buf + SF_INTPART;
1N/A }
1N/A else n = 0;
1N/A
1N/A /* remaining number of digits to compute; add 1 for later rounding */
1N/A n = (((format&SFFMT_EFORMAT) || *decpt <= 0) ? 1 : *decpt+1) - n;
1N/A if(n_digit > 0)
1N/A { if(n_digit > LDBL_DIG)
1N/A n_digit = LDBL_DIG;
1N/A n += n_digit;
1N/A }
1N/A
1N/A if((ep = (sp+n)) > (endsp = buf+(size-2)))
1N/A ep = endsp;
1N/A if(sp > ep)
1N/A sp = ep;
1N/A else
1N/A {
1N/A if((format&SFFMT_EFORMAT) && *decpt == 0 && f > 0.)
1N/A { Sfdouble_t d;
1N/A while((long)(d = f*10.) == 0)
1N/A { f = d;
1N/A *decpt -= 1;
1N/A }
1N/A }
1N/A
1N/A while(sp < ep)
1N/A { /* generate fractional digits */
1N/A if(f <= 0.)
1N/A { /* fill with 0's */
1N/A do { *sp++ = '0'; } while(sp < ep);
1N/A goto done;
1N/A }
1N/A else if((n = (long)(f *= 10.)) < 10)
1N/A { *sp++ = '0' + n;
1N/A f -= n;
1N/A }
1N/A else /* n == 10 */
1N/A { do { *sp++ = '9'; } while(sp < ep);
1N/A }
1N/A }
1N/A }
1N/A } else
1N/A#endif
1N/A { double f = *(double*)vp;
1N/A
1N/A if(isnan(f))
1N/A {
1N/A#if _lib_signbit
1N/A if (signbit(f))
1N/A#else
1N/A if (f < 0)
1N/A#endif
1N/A *sign = 1;
1N/A return SF_NAN;
1N/A }
1N/A#if _lib_isinf
1N/A if (n = isinf(f))
1N/A {
1N/A#if _lib_signbit
1N/A if (signbit(f))
1N/A#else
1N/A if (n < 0 || f < 0)
1N/A#endif
1N/A *sign = 1;
1N/A return SF_INF;
1N/A }
1N/A#endif
1N/A#if _c99_in_the_wild
1N/A# if _lib_signbit
1N/A if (signbit(f))
1N/A# else
1N/A# if _lib_copysign
1N/A if (copysign(1.0, f) < 0.0)
1N/A# else
1N/A if (f < 0.0)
1N/A# endif
1N/A# endif
1N/A { f = -f;
1N/A *sign = 1;
1N/A }
1N/A# if _lib_fpclassify
1N/A switch (fpclassify(f))
1N/A {
1N/A case FP_INFINITE:
1N/A return SF_INF;
1N/A case FP_NAN:
1N/A return SF_NAN;
1N/A case FP_ZERO:
1N/A return SF_ZERO;
1N/A }
1N/A# endif
1N/A#else
1N/A# if _lib_signbit
1N/A if (signbit(f))
1N/A# else
1N/A if (f < 0.0 || f == 0.0 && neg0d(f))
1N/A# endif
1N/A { f = -f;
1N/A *sign = 1;
1N/A }
1N/A#endif
1N/A if(f < DBL_MIN)
1N/A return SF_ZERO;
1N/A if(f > DBL_MAX)
1N/A return SF_INF;
1N/A
1N/A if(format & SFFMT_AFORMAT)
1N/A { double g;
1N/A b = sp = buf;
1N/A ep = (format & SFFMT_UPPER) ? ux : lx;
1N/A if(n_digit <= 0 || n_digit >= (size - 9))
1N/A n_digit = size - 9;
1N/A endsp = sp + n_digit + 1;
1N/A
1N/A g = frexp(f, &x);
1N/A *decpt = x;
1N/A f = ldexp(g, 8 * sizeof(m) - 3);
1N/A
1N/A for (;;)
1N/A { m = f;
1N/A x = 8 * sizeof(m);
1N/A while ((x -= 4) >= 0)
1N/A { *sp++ = ep[(m >> x) & 0xf];
1N/A if (sp >= endsp)
1N/A goto around;
1N/A }
1N/A f -= m;
1N/A f = ldexp(f, 8 * sizeof(m));
1N/A }
1N/A }
1N/A n = 0;
1N/A if(f >= (double)CVT_DBL_MAXINT)
1N/A { /* scale to a small enough number to fit an int */
1N/A v = SF_MAXEXP10-1;
1N/A do
1N/A { if(f < _Sfpos10[v])
1N/A v -= 1;
1N/A else
1N/A { f *= _Sfneg10[v];
1N/A if((n += (1<<v)) >= SF_IDIGITS)
1N/A return SF_INF;
1N/A }
1N/A } while(f >= (double)CVT_DBL_MAXINT);
1N/A }
1N/A else if(f > 0.0 && f < 1e-8)
1N/A { /* scale to avoid excessive multiply by 10 below */
1N/A v = SF_MAXEXP10-1;
1N/A do
1N/A { if(f <= _Sfneg10[v])
1N/A { f *= _Sfpos10[v];
1N/A if((n += (1<<v)) >= SF_IDIGITS)
1N/A return SF_INF;
1N/A }
1N/A else if(--v < 0)
1N/A break;
1N/A } while(f < 0.1);
1N/A n = -n;
1N/A }
1N/A *decpt = (int)n;
1N/A
1N/A b = sp = buf + SF_INTPART;
1N/A if((v = (CVT_DBL_INT)f) != 0)
1N/A { /* translate the integer part */
1N/A f -= (double)v;
1N/A
1N/A sfucvt(v,sp,n,ep,CVT_DBL_INT,unsigned CVT_DBL_INT);
1N/A
1N/A n = b-sp;
1N/A if((*decpt += (int)n) >= SF_IDIGITS)
1N/A return SF_INF;
1N/A b = sp;
1N/A sp = buf + SF_INTPART;
1N/A }
1N/A else n = 0;
1N/A
1N/A /* remaining number of digits to compute; add 1 for later rounding */
1N/A n = (((format&SFFMT_EFORMAT) || *decpt <= 0) ? 1 : *decpt+1) - n;
1N/A if(n_digit > 0)
1N/A { if(n_digit > DBL_DIG)
1N/A n_digit = DBL_DIG;
1N/A n += n_digit;
1N/A }
1N/A
1N/A if((ep = (sp+n)) > (endsp = buf+(size-2)))
1N/A ep = endsp;
1N/A if(sp > ep)
1N/A sp = ep;
1N/A else
1N/A {
1N/A if((format&SFFMT_EFORMAT) && *decpt == 0 && f > 0.)
1N/A { reg double d;
1N/A while((long)(d = f*10.) == 0)
1N/A { f = d;
1N/A *decpt -= 1;
1N/A }
1N/A }
1N/A
1N/A while(sp < ep)
1N/A { /* generate fractional digits */
1N/A if(f <= 0.)
1N/A { /* fill with 0's */
1N/A do { *sp++ = '0'; } while(sp < ep);
1N/A goto done;
1N/A }
1N/A else if((n = (long)(f *= 10.)) < 10)
1N/A { *sp++ = (char)('0' + n);
1N/A f -= n;
1N/A }
1N/A else /* n == 10 */
1N/A { do { *sp++ = '9'; } while(sp < ep);
1N/A break;
1N/A }
1N/A }
1N/A }
1N/A }
1N/A
1N/A if(ep <= b)
1N/A ep = b+1;
1N/A else if(ep < endsp)
1N/A { /* round the last digit */
1N/A *--sp += 5;
1N/A while(*sp > '9')
1N/A { *sp = '0';
1N/A if(sp > b)
1N/A *--sp += 1;
1N/A else
1N/A { /* next power of 10 */
1N/A *sp = '1';
1N/A *decpt += 1;
1N/A if(!(format&SFFMT_EFORMAT))
1N/A { /* add one more 0 for %f precision */
1N/A ep[-1] = '0';
1N/A ep += 1;
1N/A }
1N/A }
1N/A }
1N/A }
1N/A
1N/A done:
1N/A *--ep = '\0';
1N/A if(len)
1N/A *len = ep-b;
1N/A return b;
1N/A around:
1N/A if (((m >> x) & 0xf) >= 8)
1N/A { t = sp - 1;
1N/A for (;;)
1N/A { if (--t <= b)
1N/A { (*decpt)++;
1N/A break;
1N/A }
1N/A switch (*t)
1N/A {
1N/A case 'f':
1N/A case 'F':
1N/A *t = '0';
1N/A continue;
1N/A case '9':
1N/A *t = ep[10];
1N/A break;
1N/A default:
1N/A (*t)++;
1N/A break;
1N/A }
1N/A break;
1N/A }
1N/A }
1N/A ep = sp + 1;
1N/A goto done;
1N/A}