xref: /illumos-gate/usr/src/contrib/ast/src/lib/libast/sfio/sfcvt.c (revision b30d193948be5a7794d7ae3ba0ed9c2f72c88e0f)
1*b30d1939SAndy Fiddaman /***********************************************************************
2*b30d1939SAndy Fiddaman *                                                                      *
3*b30d1939SAndy Fiddaman *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1985-2012 AT&T Intellectual Property          *
5*b30d1939SAndy Fiddaman *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
7*b30d1939SAndy Fiddaman *                    by AT&T Intellectual Property                     *
8*b30d1939SAndy Fiddaman *                                                                      *
9*b30d1939SAndy Fiddaman *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*b30d1939SAndy Fiddaman *                                                                      *
13*b30d1939SAndy Fiddaman *              Information and Software Systems Research               *
14*b30d1939SAndy Fiddaman *                            AT&T Research                             *
15*b30d1939SAndy Fiddaman *                           Florham Park NJ                            *
16*b30d1939SAndy Fiddaman *                                                                      *
17*b30d1939SAndy Fiddaman *                 Glenn Fowler <gsf@research.att.com>                  *
18*b30d1939SAndy Fiddaman *                  David Korn <dgk@research.att.com>                   *
19*b30d1939SAndy Fiddaman *                   Phong Vo <kpv@research.att.com>                    *
20*b30d1939SAndy Fiddaman *                                                                      *
21*b30d1939SAndy Fiddaman ***********************************************************************/
22*b30d1939SAndy Fiddaman #if __STDC__
23*b30d1939SAndy Fiddaman #include	"FEATURE/standards"
24*b30d1939SAndy Fiddaman #endif
25*b30d1939SAndy Fiddaman #include	"sfhdr.h"
26*b30d1939SAndy Fiddaman 
27*b30d1939SAndy Fiddaman /*	Convert a floating point value to ASCII.
28*b30d1939SAndy Fiddaman **
29*b30d1939SAndy Fiddaman **	Written by Kiem-Phong Vo and Glenn Fowler (SFFMT_AFORMAT)
30*b30d1939SAndy Fiddaman */
31*b30d1939SAndy Fiddaman 
32*b30d1939SAndy Fiddaman static char		*lc_inf = "inf", *uc_inf = "INF";
33*b30d1939SAndy Fiddaman static char		*lc_nan = "nan", *uc_nan = "NAN";
34*b30d1939SAndy Fiddaman static char		*Zero = "0";
35*b30d1939SAndy Fiddaman #define SF_INF		((_Sfi = 3), strlcpy(buf, (format & SFFMT_UPPER) ? uc_inf : lc_inf, size), buf)
36*b30d1939SAndy Fiddaman #define SF_NAN		((_Sfi = 3), strlcpy(buf, (format & SFFMT_UPPER) ? uc_nan : lc_nan, size), buf)
37*b30d1939SAndy Fiddaman #define SF_ZERO		((_Sfi = 1), strlcpy(buf, Zero, size), buf)
38*b30d1939SAndy Fiddaman #define SF_INTPART	(SF_IDIGITS/2)
39*b30d1939SAndy Fiddaman 
40*b30d1939SAndy Fiddaman #if !_lib_isnan
41*b30d1939SAndy Fiddaman #undef	isnan
42*b30d1939SAndy Fiddaman #undef	isnanl
43*b30d1939SAndy Fiddaman #if _lib_fpclassify
44*b30d1939SAndy Fiddaman #define isnan(n)	(fpclassify(n)==FP_NAN)
45*b30d1939SAndy Fiddaman #define isnanl(n)	(fpclassify(n)==FP_NAN)
46*b30d1939SAndy Fiddaman #else
47*b30d1939SAndy Fiddaman #error "This is an invalid test for NaN"
48*b30d1939SAndy Fiddaman #define isnan(n)	(memcmp((void*)&n,(void*)&_Sfdnan,sizeof(n))==0)
49*b30d1939SAndy Fiddaman #define isnanl(n)	(memcmp((void*)&n,(void*)&_Sflnan,sizeof(n))==0)
50*b30d1939SAndy Fiddaman #endif
51*b30d1939SAndy Fiddaman #else
52*b30d1939SAndy Fiddaman #if !_lib_isnanl
53*b30d1939SAndy Fiddaman #undef	isnanl
54*b30d1939SAndy Fiddaman #define isnanl(n)	isnan(n)
55*b30d1939SAndy Fiddaman #endif
56*b30d1939SAndy Fiddaman #endif
57*b30d1939SAndy Fiddaman 
58*b30d1939SAndy Fiddaman #if !_lib_signbit
59*b30d1939SAndy Fiddaman #if !_ast_fltmax_double
neg0ld(Sfdouble_t f)60*b30d1939SAndy Fiddaman static int neg0ld(Sfdouble_t f)
61*b30d1939SAndy Fiddaman {
62*b30d1939SAndy Fiddaman 	Sfdouble_t	z = 0;
63*b30d1939SAndy Fiddaman 	z = -z;
64*b30d1939SAndy Fiddaman 	return !memcmp(&f, &z, sizeof(f));
65*b30d1939SAndy Fiddaman }
66*b30d1939SAndy Fiddaman #endif
neg0d(double f)67*b30d1939SAndy Fiddaman static int neg0d(double f)
68*b30d1939SAndy Fiddaman {
69*b30d1939SAndy Fiddaman 	double		z = 0;
70*b30d1939SAndy Fiddaman 	z = -z;
71*b30d1939SAndy Fiddaman 	return !memcmp(&f, &z, sizeof(f));
72*b30d1939SAndy Fiddaman }
73*b30d1939SAndy Fiddaman #endif
74*b30d1939SAndy Fiddaman 
75*b30d1939SAndy Fiddaman #if ULONG_DIG && ULONG_DIG < (DBL_DIG-1)
76*b30d1939SAndy Fiddaman #define CVT_LDBL_INT	long
77*b30d1939SAndy Fiddaman #define CVT_LDBL_MAXINT	LONG_MAX
78*b30d1939SAndy Fiddaman #else
79*b30d1939SAndy Fiddaman #if UINT_DIG && UINT_DIG < (DBL_DIG-1)
80*b30d1939SAndy Fiddaman #define CVT_LDBL_INT	int
81*b30d1939SAndy Fiddaman #define CVT_LDBL_MAXINT	INT_MAX
82*b30d1939SAndy Fiddaman #else
83*b30d1939SAndy Fiddaman #define CVT_LDBL_INT	long
84*b30d1939SAndy Fiddaman #define CVT_LDBL_MAXINT	SF_MAXLONG
85*b30d1939SAndy Fiddaman #endif
86*b30d1939SAndy Fiddaman #endif
87*b30d1939SAndy Fiddaman 
88*b30d1939SAndy Fiddaman #if ULONG_DIG && ULONG_DIG < (DBL_DIG-1)
89*b30d1939SAndy Fiddaman #define CVT_DBL_INT	long
90*b30d1939SAndy Fiddaman #define CVT_DBL_MAXINT	LONG_MAX
91*b30d1939SAndy Fiddaman #else
92*b30d1939SAndy Fiddaman #if UINT_DIG && UINT_DIG < (DBL_DIG-1)
93*b30d1939SAndy Fiddaman #define CVT_DBL_INT	int
94*b30d1939SAndy Fiddaman #define CVT_DBL_MAXINT	INT_MAX
95*b30d1939SAndy Fiddaman #else
96*b30d1939SAndy Fiddaman #define CVT_DBL_INT	long
97*b30d1939SAndy Fiddaman #define CVT_DBL_MAXINT	SF_MAXLONG
98*b30d1939SAndy Fiddaman #endif
99*b30d1939SAndy Fiddaman #endif
100*b30d1939SAndy Fiddaman 
101*b30d1939SAndy Fiddaman #if __STD_C
_sfcvt(Void_t * vp,char * buf,size_t size,int n_digit,int * decpt,int * sign,int * len,int format)102*b30d1939SAndy Fiddaman char* _sfcvt(Void_t* vp, char* buf, size_t size, int n_digit,
103*b30d1939SAndy Fiddaman 		int* decpt, int* sign, int* len, int format)
104*b30d1939SAndy Fiddaman #else
105*b30d1939SAndy Fiddaman char* _sfcvt(vp,buf,size,n_digit,decpt,sign,len,format)
106*b30d1939SAndy Fiddaman Void_t*		vp;		/* pointer to value to convert	*/
107*b30d1939SAndy Fiddaman char*		buf;		/* conversion goes here		*/
108*b30d1939SAndy Fiddaman size_t		size;		/* size of buf			*/
109*b30d1939SAndy Fiddaman int		n_digit;	/* number of digits wanted	*/
110*b30d1939SAndy Fiddaman int*		decpt;		/* to return decimal point	*/
111*b30d1939SAndy Fiddaman int*		sign;		/* to return sign		*/
112*b30d1939SAndy Fiddaman int*		len;		/* return string length		*/
113*b30d1939SAndy Fiddaman int		format;		/* conversion format		*/
114*b30d1939SAndy Fiddaman #endif
115*b30d1939SAndy Fiddaman {
116*b30d1939SAndy Fiddaman 	reg char		*sp;
117*b30d1939SAndy Fiddaman 	reg long		n, v;
118*b30d1939SAndy Fiddaman 	reg char		*ep, *b, *endsp, *t;
119*b30d1939SAndy Fiddaman 	int			x;
120*b30d1939SAndy Fiddaman 	_ast_flt_unsigned_max_t	m;
121*b30d1939SAndy Fiddaman 
122*b30d1939SAndy Fiddaman 	static char		lx[] = "0123456789abcdef";
123*b30d1939SAndy Fiddaman 	static char		ux[] = "0123456789ABCDEF";
124*b30d1939SAndy Fiddaman 
125*b30d1939SAndy Fiddaman 	*sign = *decpt = 0;
126*b30d1939SAndy Fiddaman 
127*b30d1939SAndy Fiddaman #if !_ast_fltmax_double
128*b30d1939SAndy Fiddaman 	if(format&SFFMT_LDOUBLE)
129*b30d1939SAndy Fiddaman 	{	Sfdouble_t	f = *(Sfdouble_t*)vp;
130*b30d1939SAndy Fiddaman 
131*b30d1939SAndy Fiddaman 		if(isnanl(f))
132*b30d1939SAndy Fiddaman 		{
133*b30d1939SAndy Fiddaman #if _lib_signbit
134*b30d1939SAndy Fiddaman 			if (signbit(f))
135*b30d1939SAndy Fiddaman #else
136*b30d1939SAndy Fiddaman 			if (f < 0)
137*b30d1939SAndy Fiddaman #endif
138*b30d1939SAndy Fiddaman 				*sign = 1;
139*b30d1939SAndy Fiddaman 			return SF_NAN;
140*b30d1939SAndy Fiddaman 		}
141*b30d1939SAndy Fiddaman #if _lib_isinf
142*b30d1939SAndy Fiddaman 		if (n = isinf(f))
143*b30d1939SAndy Fiddaman 		{
144*b30d1939SAndy Fiddaman #if _lib_signbit
145*b30d1939SAndy Fiddaman 			if (signbit(f))
146*b30d1939SAndy Fiddaman #else
147*b30d1939SAndy Fiddaman 			if (n < 0 || f < 0)
148*b30d1939SAndy Fiddaman #endif
149*b30d1939SAndy Fiddaman 				*sign = 1;
150*b30d1939SAndy Fiddaman 			return SF_INF;
151*b30d1939SAndy Fiddaman 		}
152*b30d1939SAndy Fiddaman #endif
153*b30d1939SAndy Fiddaman # if _c99_in_the_wild
154*b30d1939SAndy Fiddaman #  if _lib_signbit
155*b30d1939SAndy Fiddaman 		if (signbit(f))
156*b30d1939SAndy Fiddaman #  else
157*b30d1939SAndy Fiddaman #   if _lib_copysignl
158*b30d1939SAndy Fiddaman 		if (copysignl(1.0, f) < 0.0)
159*b30d1939SAndy Fiddaman #   else
160*b30d1939SAndy Fiddaman #    if _lib_copysign
161*b30d1939SAndy Fiddaman 		if (copysign(1.0, (double)f) < 0.0)
162*b30d1939SAndy Fiddaman #    else
163*b30d1939SAndy Fiddaman 		if (f < 0.0)
164*b30d1939SAndy Fiddaman #    endif
165*b30d1939SAndy Fiddaman #   endif
166*b30d1939SAndy Fiddaman #  endif
167*b30d1939SAndy Fiddaman 		{	f = -f;
168*b30d1939SAndy Fiddaman 			*sign = 1;
169*b30d1939SAndy Fiddaman 		}
170*b30d1939SAndy Fiddaman #  if _lib_fpclassify
171*b30d1939SAndy Fiddaman 		switch (fpclassify(f))
172*b30d1939SAndy Fiddaman 		{
173*b30d1939SAndy Fiddaman 		case FP_INFINITE:
174*b30d1939SAndy Fiddaman 			return SF_INF;
175*b30d1939SAndy Fiddaman 		case FP_NAN:
176*b30d1939SAndy Fiddaman 			return SF_NAN;
177*b30d1939SAndy Fiddaman 		case FP_ZERO:
178*b30d1939SAndy Fiddaman 			return SF_ZERO;
179*b30d1939SAndy Fiddaman 		}
180*b30d1939SAndy Fiddaman #  endif
181*b30d1939SAndy Fiddaman # else
182*b30d1939SAndy Fiddaman #  if _lib_signbit
183*b30d1939SAndy Fiddaman 		if (signbit(f))
184*b30d1939SAndy Fiddaman #  else
185*b30d1939SAndy Fiddaman 		if (f < 0.0 || f == 0.0 && neg0ld(f))
186*b30d1939SAndy Fiddaman #  endif
187*b30d1939SAndy Fiddaman 		{	f = -f;
188*b30d1939SAndy Fiddaman 			*sign = 1;
189*b30d1939SAndy Fiddaman 		}
190*b30d1939SAndy Fiddaman # endif
191*b30d1939SAndy Fiddaman 		if(f < LDBL_MIN)
192*b30d1939SAndy Fiddaman 			return SF_ZERO;
193*b30d1939SAndy Fiddaman 		if(f > LDBL_MAX)
194*b30d1939SAndy Fiddaman 			return SF_INF;
195*b30d1939SAndy Fiddaman 
196*b30d1939SAndy Fiddaman 		if(format & SFFMT_AFORMAT)
197*b30d1939SAndy Fiddaman 		{	Sfdouble_t	g;
198*b30d1939SAndy Fiddaman 			b = sp = buf;
199*b30d1939SAndy Fiddaman 			ep = (format & SFFMT_UPPER) ? ux : lx;
200*b30d1939SAndy Fiddaman 			if(n_digit <= 0 || n_digit >= (size - 9))
201*b30d1939SAndy Fiddaman 				n_digit = size - 9;
202*b30d1939SAndy Fiddaman 			endsp = sp + n_digit + 1;
203*b30d1939SAndy Fiddaman 
204*b30d1939SAndy Fiddaman 			g = frexpl(f, &x);
205*b30d1939SAndy Fiddaman 			*decpt = x;
206*b30d1939SAndy Fiddaman 			f = ldexpl(g, 8 * sizeof(m) - 3);
207*b30d1939SAndy Fiddaman 
208*b30d1939SAndy Fiddaman 			for (;;)
209*b30d1939SAndy Fiddaman 			{	m = f;
210*b30d1939SAndy Fiddaman 				x = 8 * sizeof(m);
211*b30d1939SAndy Fiddaman 				while ((x -= 4) >= 0)
212*b30d1939SAndy Fiddaman 				{	*sp++ = ep[(m >> x) & 0xf];
213*b30d1939SAndy Fiddaman 					if (sp >= endsp)
214*b30d1939SAndy Fiddaman 						goto around;
215*b30d1939SAndy Fiddaman 				}
216*b30d1939SAndy Fiddaman 				f -= m;
217*b30d1939SAndy Fiddaman 				f = ldexpl(f, 8 * sizeof(m));
218*b30d1939SAndy Fiddaman 			}
219*b30d1939SAndy Fiddaman 		}
220*b30d1939SAndy Fiddaman 
221*b30d1939SAndy Fiddaman 		n = 0;
222*b30d1939SAndy Fiddaman 		if(f >= (Sfdouble_t)CVT_LDBL_MAXINT)
223*b30d1939SAndy Fiddaman 		{	/* scale to a small enough number to fit an int */
224*b30d1939SAndy Fiddaman 			v = SF_MAXEXP10-1;
225*b30d1939SAndy Fiddaman 			do
226*b30d1939SAndy Fiddaman 			{	if(f < _Sfpos10[v])
227*b30d1939SAndy Fiddaman 					v -= 1;
228*b30d1939SAndy Fiddaman 				else
229*b30d1939SAndy Fiddaman 				{
230*b30d1939SAndy Fiddaman 					f *= _Sfneg10[v];
231*b30d1939SAndy Fiddaman 					if((n += (1<<v)) >= SF_IDIGITS)
232*b30d1939SAndy Fiddaman 						return SF_INF;
233*b30d1939SAndy Fiddaman 				}
234*b30d1939SAndy Fiddaman 			} while(f >= (Sfdouble_t)CVT_LDBL_MAXINT);
235*b30d1939SAndy Fiddaman 		}
236*b30d1939SAndy Fiddaman 		else if(f > 0.0 && f < 0.1)
237*b30d1939SAndy Fiddaman 		{	/* scale to avoid excessive multiply by 10 below */
238*b30d1939SAndy Fiddaman 			v = SF_MAXEXP10-1;
239*b30d1939SAndy Fiddaman 			do
240*b30d1939SAndy Fiddaman 			{	if(f <= _Sfneg10[v])
241*b30d1939SAndy Fiddaman 				{	f *= _Sfpos10[v];
242*b30d1939SAndy Fiddaman 					if((n += (1<<v)) >= SF_IDIGITS)
243*b30d1939SAndy Fiddaman 						return SF_INF;
244*b30d1939SAndy Fiddaman 				}
245*b30d1939SAndy Fiddaman 				else if (--v < 0)
246*b30d1939SAndy Fiddaman 					break;
247*b30d1939SAndy Fiddaman 			} while(f < 0.1);
248*b30d1939SAndy Fiddaman 			n = -n;
249*b30d1939SAndy Fiddaman 		}
250*b30d1939SAndy Fiddaman 		*decpt = (int)n;
251*b30d1939SAndy Fiddaman 
252*b30d1939SAndy Fiddaman 		b = sp = buf + SF_INTPART;
253*b30d1939SAndy Fiddaman 		if((v = (CVT_LDBL_INT)f) != 0)
254*b30d1939SAndy Fiddaman 		{	/* translate the integer part */
255*b30d1939SAndy Fiddaman 			f -= (Sfdouble_t)v;
256*b30d1939SAndy Fiddaman 
257*b30d1939SAndy Fiddaman 			sfucvt(v,sp,n,ep,CVT_LDBL_INT,unsigned CVT_LDBL_INT);
258*b30d1939SAndy Fiddaman 
259*b30d1939SAndy Fiddaman 			n = b-sp;
260*b30d1939SAndy Fiddaman 			if((*decpt += (int)n) >= SF_IDIGITS)
261*b30d1939SAndy Fiddaman 				return SF_INF;
262*b30d1939SAndy Fiddaman 			b = sp;
263*b30d1939SAndy Fiddaman 			sp = buf + SF_INTPART;
264*b30d1939SAndy Fiddaman 		}
265*b30d1939SAndy Fiddaman 		else	n = 0;
266*b30d1939SAndy Fiddaman 
267*b30d1939SAndy Fiddaman 		/* remaining number of digits to compute; add 1 for later rounding */
268*b30d1939SAndy Fiddaman 		n = (((format&SFFMT_EFORMAT) || *decpt <= 0) ? 1 : *decpt+1) - n;
269*b30d1939SAndy Fiddaman 		if(n_digit > 0)
270*b30d1939SAndy Fiddaman 		{	if(n_digit > LDBL_DIG)
271*b30d1939SAndy Fiddaman 				n_digit = LDBL_DIG;
272*b30d1939SAndy Fiddaman 			n += n_digit;
273*b30d1939SAndy Fiddaman 		}
274*b30d1939SAndy Fiddaman 
275*b30d1939SAndy Fiddaman 		if((ep = (sp+n)) > (endsp = buf+(size-2)))
276*b30d1939SAndy Fiddaman 			ep = endsp;
277*b30d1939SAndy Fiddaman 		if(sp > ep)
278*b30d1939SAndy Fiddaman 			sp = ep;
279*b30d1939SAndy Fiddaman 		else
280*b30d1939SAndy Fiddaman 		{
281*b30d1939SAndy Fiddaman 			if((format&SFFMT_EFORMAT) && *decpt == 0 && f > 0.)
282*b30d1939SAndy Fiddaman 			{	Sfdouble_t	d;
283*b30d1939SAndy Fiddaman 				while((long)(d = f*10.) == 0)
284*b30d1939SAndy Fiddaman 				{	f = d;
285*b30d1939SAndy Fiddaman 					*decpt -= 1;
286*b30d1939SAndy Fiddaman 				}
287*b30d1939SAndy Fiddaman 			}
288*b30d1939SAndy Fiddaman 
289*b30d1939SAndy Fiddaman 			while(sp < ep)
290*b30d1939SAndy Fiddaman 			{	/* generate fractional digits */
291*b30d1939SAndy Fiddaman 				if(f <= 0.)
292*b30d1939SAndy Fiddaman 				{	/* fill with 0's */
293*b30d1939SAndy Fiddaman 					do { *sp++ = '0'; } while(sp < ep);
294*b30d1939SAndy Fiddaman 					goto done;
295*b30d1939SAndy Fiddaman 				}
296*b30d1939SAndy Fiddaman 				else if((n = (long)(f *= 10.)) < 10)
297*b30d1939SAndy Fiddaman 				{	*sp++ = '0' + n;
298*b30d1939SAndy Fiddaman 					f -= n;
299*b30d1939SAndy Fiddaman 				}
300*b30d1939SAndy Fiddaman 				else /* n == 10 */
301*b30d1939SAndy Fiddaman 				{	do { *sp++ = '9'; } while(sp < ep);
302*b30d1939SAndy Fiddaman 				}
303*b30d1939SAndy Fiddaman 			}
304*b30d1939SAndy Fiddaman 		}
305*b30d1939SAndy Fiddaman 	} else
306*b30d1939SAndy Fiddaman #endif
307*b30d1939SAndy Fiddaman 	{	double	f = *(double*)vp;
308*b30d1939SAndy Fiddaman 
309*b30d1939SAndy Fiddaman 		if(isnan(f))
310*b30d1939SAndy Fiddaman 		{
311*b30d1939SAndy Fiddaman #if _lib_signbit
312*b30d1939SAndy Fiddaman 			if (signbit(f))
313*b30d1939SAndy Fiddaman #else
314*b30d1939SAndy Fiddaman 			if (f < 0)
315*b30d1939SAndy Fiddaman #endif
316*b30d1939SAndy Fiddaman 				*sign = 1;
317*b30d1939SAndy Fiddaman 			return SF_NAN;
318*b30d1939SAndy Fiddaman 		}
319*b30d1939SAndy Fiddaman #if _lib_isinf
320*b30d1939SAndy Fiddaman 		if (n = isinf(f))
321*b30d1939SAndy Fiddaman 		{
322*b30d1939SAndy Fiddaman #if _lib_signbit
323*b30d1939SAndy Fiddaman 			if (signbit(f))
324*b30d1939SAndy Fiddaman #else
325*b30d1939SAndy Fiddaman 			if (n < 0 || f < 0)
326*b30d1939SAndy Fiddaman #endif
327*b30d1939SAndy Fiddaman 				*sign = 1;
328*b30d1939SAndy Fiddaman 			return SF_INF;
329*b30d1939SAndy Fiddaman 		}
330*b30d1939SAndy Fiddaman #endif
331*b30d1939SAndy Fiddaman #if _c99_in_the_wild
332*b30d1939SAndy Fiddaman # if _lib_signbit
333*b30d1939SAndy Fiddaman 		if (signbit(f))
334*b30d1939SAndy Fiddaman # else
335*b30d1939SAndy Fiddaman #  if _lib_copysign
336*b30d1939SAndy Fiddaman 		if (copysign(1.0, f) < 0.0)
337*b30d1939SAndy Fiddaman #  else
338*b30d1939SAndy Fiddaman 		if (f < 0.0)
339*b30d1939SAndy Fiddaman #  endif
340*b30d1939SAndy Fiddaman # endif
341*b30d1939SAndy Fiddaman 		{	f = -f;
342*b30d1939SAndy Fiddaman 			*sign = 1;
343*b30d1939SAndy Fiddaman 		}
344*b30d1939SAndy Fiddaman # if _lib_fpclassify
345*b30d1939SAndy Fiddaman 		switch (fpclassify(f))
346*b30d1939SAndy Fiddaman 		{
347*b30d1939SAndy Fiddaman 		case FP_INFINITE:
348*b30d1939SAndy Fiddaman 			return SF_INF;
349*b30d1939SAndy Fiddaman 		case FP_NAN:
350*b30d1939SAndy Fiddaman 			return SF_NAN;
351*b30d1939SAndy Fiddaman 		case FP_ZERO:
352*b30d1939SAndy Fiddaman 			return SF_ZERO;
353*b30d1939SAndy Fiddaman 		}
354*b30d1939SAndy Fiddaman # endif
355*b30d1939SAndy Fiddaman #else
356*b30d1939SAndy Fiddaman # if _lib_signbit
357*b30d1939SAndy Fiddaman 		if (signbit(f))
358*b30d1939SAndy Fiddaman # else
359*b30d1939SAndy Fiddaman 		if (f < 0.0 || f == 0.0 && neg0d(f))
360*b30d1939SAndy Fiddaman # endif
361*b30d1939SAndy Fiddaman 		{	f = -f;
362*b30d1939SAndy Fiddaman 			*sign = 1;
363*b30d1939SAndy Fiddaman 		}
364*b30d1939SAndy Fiddaman #endif
365*b30d1939SAndy Fiddaman 		if(f < DBL_MIN)
366*b30d1939SAndy Fiddaman 			return SF_ZERO;
367*b30d1939SAndy Fiddaman 		if(f > DBL_MAX)
368*b30d1939SAndy Fiddaman 			return SF_INF;
369*b30d1939SAndy Fiddaman 
370*b30d1939SAndy Fiddaman 		if(format & SFFMT_AFORMAT)
371*b30d1939SAndy Fiddaman 		{	double		g;
372*b30d1939SAndy Fiddaman 			b = sp = buf;
373*b30d1939SAndy Fiddaman 			ep = (format & SFFMT_UPPER) ? ux : lx;
374*b30d1939SAndy Fiddaman 			if(n_digit <= 0 || n_digit >= (size - 9))
375*b30d1939SAndy Fiddaman 				n_digit = size - 9;
376*b30d1939SAndy Fiddaman 			endsp = sp + n_digit + 1;
377*b30d1939SAndy Fiddaman 
378*b30d1939SAndy Fiddaman 			g = frexp(f, &x);
379*b30d1939SAndy Fiddaman 			*decpt = x;
380*b30d1939SAndy Fiddaman 			f = ldexp(g, 8 * sizeof(m) - 3);
381*b30d1939SAndy Fiddaman 
382*b30d1939SAndy Fiddaman 			for (;;)
383*b30d1939SAndy Fiddaman 			{	m = f;
384*b30d1939SAndy Fiddaman 				x = 8 * sizeof(m);
385*b30d1939SAndy Fiddaman 				while ((x -= 4) >= 0)
386*b30d1939SAndy Fiddaman 				{	*sp++ = ep[(m >> x) & 0xf];
387*b30d1939SAndy Fiddaman 					if (sp >= endsp)
388*b30d1939SAndy Fiddaman 						goto around;
389*b30d1939SAndy Fiddaman 				}
390*b30d1939SAndy Fiddaman 				f -= m;
391*b30d1939SAndy Fiddaman 				f = ldexp(f, 8 * sizeof(m));
392*b30d1939SAndy Fiddaman 			}
393*b30d1939SAndy Fiddaman 		}
394*b30d1939SAndy Fiddaman 		n = 0;
395*b30d1939SAndy Fiddaman 		if(f >= (double)CVT_DBL_MAXINT)
396*b30d1939SAndy Fiddaman 		{	/* scale to a small enough number to fit an int */
397*b30d1939SAndy Fiddaman 			v = SF_MAXEXP10-1;
398*b30d1939SAndy Fiddaman 			do
399*b30d1939SAndy Fiddaman 			{	if(f < _Sfpos10[v])
400*b30d1939SAndy Fiddaman 					v -= 1;
401*b30d1939SAndy Fiddaman 				else
402*b30d1939SAndy Fiddaman 				{	f *= _Sfneg10[v];
403*b30d1939SAndy Fiddaman 					if((n += (1<<v)) >= SF_IDIGITS)
404*b30d1939SAndy Fiddaman 						return SF_INF;
405*b30d1939SAndy Fiddaman 				}
406*b30d1939SAndy Fiddaman 			} while(f >= (double)CVT_DBL_MAXINT);
407*b30d1939SAndy Fiddaman 		}
408*b30d1939SAndy Fiddaman 		else if(f > 0.0 && f < 1e-8)
409*b30d1939SAndy Fiddaman 		{	/* scale to avoid excessive multiply by 10 below */
410*b30d1939SAndy Fiddaman 			v = SF_MAXEXP10-1;
411*b30d1939SAndy Fiddaman 			do
412*b30d1939SAndy Fiddaman 			{	if(f <= _Sfneg10[v])
413*b30d1939SAndy Fiddaman 				{	f *= _Sfpos10[v];
414*b30d1939SAndy Fiddaman 					if((n += (1<<v)) >= SF_IDIGITS)
415*b30d1939SAndy Fiddaman 						return SF_INF;
416*b30d1939SAndy Fiddaman 				}
417*b30d1939SAndy Fiddaman 				else if(--v < 0)
418*b30d1939SAndy Fiddaman 					break;
419*b30d1939SAndy Fiddaman 			} while(f < 0.1);
420*b30d1939SAndy Fiddaman 			n = -n;
421*b30d1939SAndy Fiddaman 		}
422*b30d1939SAndy Fiddaman 		*decpt = (int)n;
423*b30d1939SAndy Fiddaman 
424*b30d1939SAndy Fiddaman 		b = sp = buf + SF_INTPART;
425*b30d1939SAndy Fiddaman 		if((v = (CVT_DBL_INT)f) != 0)
426*b30d1939SAndy Fiddaman 		{	/* translate the integer part */
427*b30d1939SAndy Fiddaman 			f -= (double)v;
428*b30d1939SAndy Fiddaman 
429*b30d1939SAndy Fiddaman 			sfucvt(v,sp,n,ep,CVT_DBL_INT,unsigned CVT_DBL_INT);
430*b30d1939SAndy Fiddaman 
431*b30d1939SAndy Fiddaman 			n = b-sp;
432*b30d1939SAndy Fiddaman 			if((*decpt += (int)n) >= SF_IDIGITS)
433*b30d1939SAndy Fiddaman 				return SF_INF;
434*b30d1939SAndy Fiddaman 			b = sp;
435*b30d1939SAndy Fiddaman 			sp = buf + SF_INTPART;
436*b30d1939SAndy Fiddaman 		}
437*b30d1939SAndy Fiddaman 		else	n = 0;
438*b30d1939SAndy Fiddaman 
439*b30d1939SAndy Fiddaman 		/* remaining number of digits to compute; add 1 for later rounding */
440*b30d1939SAndy Fiddaman 		n = (((format&SFFMT_EFORMAT) || *decpt <= 0) ? 1 : *decpt+1) - n;
441*b30d1939SAndy Fiddaman 		if(n_digit > 0)
442*b30d1939SAndy Fiddaman 		{	if(n_digit > DBL_DIG)
443*b30d1939SAndy Fiddaman 				n_digit = DBL_DIG;
444*b30d1939SAndy Fiddaman 			n += n_digit;
445*b30d1939SAndy Fiddaman 		}
446*b30d1939SAndy Fiddaman 
447*b30d1939SAndy Fiddaman 		if((ep = (sp+n)) > (endsp = buf+(size-2)))
448*b30d1939SAndy Fiddaman 			ep = endsp;
449*b30d1939SAndy Fiddaman 		if(sp > ep)
450*b30d1939SAndy Fiddaman 			sp = ep;
451*b30d1939SAndy Fiddaman 		else
452*b30d1939SAndy Fiddaman 		{
453*b30d1939SAndy Fiddaman 			if((format&SFFMT_EFORMAT) && *decpt == 0 && f > 0.)
454*b30d1939SAndy Fiddaman 			{	reg double	d;
455*b30d1939SAndy Fiddaman 				while((long)(d = f*10.) == 0)
456*b30d1939SAndy Fiddaman 				{	f = d;
457*b30d1939SAndy Fiddaman 					*decpt -= 1;
458*b30d1939SAndy Fiddaman 				}
459*b30d1939SAndy Fiddaman 			}
460*b30d1939SAndy Fiddaman 
461*b30d1939SAndy Fiddaman 			while(sp < ep)
462*b30d1939SAndy Fiddaman 			{	/* generate fractional digits */
463*b30d1939SAndy Fiddaman 				if(f <= 0.)
464*b30d1939SAndy Fiddaman 				{	/* fill with 0's */
465*b30d1939SAndy Fiddaman 					do { *sp++ = '0'; } while(sp < ep);
466*b30d1939SAndy Fiddaman 					goto done;
467*b30d1939SAndy Fiddaman 				}
468*b30d1939SAndy Fiddaman 				else if((n = (long)(f *= 10.)) < 10)
469*b30d1939SAndy Fiddaman 				{	*sp++ = (char)('0' + n);
470*b30d1939SAndy Fiddaman 					f -= n;
471*b30d1939SAndy Fiddaman 				}
472*b30d1939SAndy Fiddaman 				else /* n == 10 */
473*b30d1939SAndy Fiddaman 				{	do { *sp++ = '9'; } while(sp < ep);
474*b30d1939SAndy Fiddaman 					break;
475*b30d1939SAndy Fiddaman 				}
476*b30d1939SAndy Fiddaman 			}
477*b30d1939SAndy Fiddaman 		}
478*b30d1939SAndy Fiddaman 	}
479*b30d1939SAndy Fiddaman 
480*b30d1939SAndy Fiddaman 	if(ep <= b)
481*b30d1939SAndy Fiddaman 		ep = b+1;
482*b30d1939SAndy Fiddaman 	else if(ep < endsp)
483*b30d1939SAndy Fiddaman 	{	/* round the last digit */
484*b30d1939SAndy Fiddaman 		*--sp += 5;
485*b30d1939SAndy Fiddaman 		while(*sp > '9')
486*b30d1939SAndy Fiddaman 		{	*sp = '0';
487*b30d1939SAndy Fiddaman 			if(sp > b)
488*b30d1939SAndy Fiddaman 				*--sp += 1;
489*b30d1939SAndy Fiddaman 			else
490*b30d1939SAndy Fiddaman 			{	/* next power of 10 */
491*b30d1939SAndy Fiddaman 				*sp = '1';
492*b30d1939SAndy Fiddaman 				*decpt += 1;
493*b30d1939SAndy Fiddaman 				if(!(format&SFFMT_EFORMAT))
494*b30d1939SAndy Fiddaman 				{	/* add one more 0 for %f precision */
495*b30d1939SAndy Fiddaman 					ep[-1] = '0';
496*b30d1939SAndy Fiddaman 					ep += 1;
497*b30d1939SAndy Fiddaman 				}
498*b30d1939SAndy Fiddaman 			}
499*b30d1939SAndy Fiddaman 		}
500*b30d1939SAndy Fiddaman 	}
501*b30d1939SAndy Fiddaman 
502*b30d1939SAndy Fiddaman  done:
503*b30d1939SAndy Fiddaman 	*--ep = '\0';
504*b30d1939SAndy Fiddaman 	if(len)
505*b30d1939SAndy Fiddaman 		*len = ep-b;
506*b30d1939SAndy Fiddaman 	return b;
507*b30d1939SAndy Fiddaman  around:
508*b30d1939SAndy Fiddaman 	if (((m >> x) & 0xf) >= 8)
509*b30d1939SAndy Fiddaman 	{	t = sp - 1;
510*b30d1939SAndy Fiddaman 		for (;;)
511*b30d1939SAndy Fiddaman 		{	if (--t <= b)
512*b30d1939SAndy Fiddaman 			{	(*decpt)++;
513*b30d1939SAndy Fiddaman 				break;
514*b30d1939SAndy Fiddaman 			}
515*b30d1939SAndy Fiddaman 			switch (*t)
516*b30d1939SAndy Fiddaman 			{
517*b30d1939SAndy Fiddaman 			case 'f':
518*b30d1939SAndy Fiddaman 			case 'F':
519*b30d1939SAndy Fiddaman 				*t = '0';
520*b30d1939SAndy Fiddaman 				continue;
521*b30d1939SAndy Fiddaman 			case '9':
522*b30d1939SAndy Fiddaman 				*t = ep[10];
523*b30d1939SAndy Fiddaman 				break;
524*b30d1939SAndy Fiddaman 			default:
525*b30d1939SAndy Fiddaman 				(*t)++;
526*b30d1939SAndy Fiddaman 				break;
527*b30d1939SAndy Fiddaman 			}
528*b30d1939SAndy Fiddaman 			break;
529*b30d1939SAndy Fiddaman 		}
530*b30d1939SAndy Fiddaman 	}
531*b30d1939SAndy Fiddaman 	ep = sp + 1;
532*b30d1939SAndy Fiddaman 	goto done;
533*b30d1939SAndy Fiddaman }
534