xref: /titanic_44/usr/src/lib/libast/common/sfio/sfcvt.c (revision edcc07547a39d6570197493a9836083bd6b2a197)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #include	"sfhdr.h"
23 
24 /*	Convert a floating point value to ASCII.
25 **
26 **	Written by Kiem-Phong Vo and Glenn Fowler (SFFMT_AFORMAT)
27 */
28 
29 static char		*lc_inf = "inf", *uc_inf = "INF";
30 static char		*lc_nan = "nan", *uc_nan = "NAN";
31 static char		*Zero = "0";
32 #define SF_INF		((_Sfi = 3), strncpy(buf, (format & SFFMT_UPPER) ? uc_inf : lc_inf, size))
33 #define SF_NAN		((_Sfi = 3), strncpy(buf, (format & SFFMT_UPPER) ? uc_nan : lc_nan, size))
34 #define SF_ZERO		((_Sfi = 1), strncpy(buf, Zero, size))
35 #define SF_INTPART	(SF_IDIGITS/2)
36 
37 #if ! _lib_isnan
38 #if _lib_fpclassify
39 #define isnan(n)	(fpclassify(n)==FP_NAN)
40 #define isnanl(n)	(fpclassify(n)==FP_NAN)
41 #else
42 #define isnan(n)	(memcmp((void*)&n,(void*)&_Sfdnan,sizeof(n))==0)
43 #define isnanl(n)	(memcmp((void*)&n,(void*)&_Sflnan,sizeof(n))==0)
44 #endif
45 #else
46 #if ! _lib_isnanl
47 #define isnanl(n)	isnan(n)
48 #endif
49 #endif
50 
51 #if __STD_C
52 char* _sfcvt(Sfdouble_t dv, char* buf, size_t size, int n_digit,
53 		int* decpt, int* sign, int* len, int format)
54 #else
55 char* _sfcvt(dv,buf,size,n_digit,decpt,sign,len,format)
56 Sfdouble_t	dv;		/* value to convert		*/
57 char*		buf;		/* conversion goes here		*/
58 size_t		size;		/* size of buf			*/
59 int		n_digit;	/* number of digits wanted	*/
60 int*		decpt;		/* to return decimal point	*/
61 int*		sign;		/* to return sign		*/
62 int*		len;		/* return string length		*/
63 int		format;		/* conversion format		*/
64 #endif
65 {
66 	reg char		*sp;
67 	reg long		n, v;
68 	reg char		*ep, *b, *endsp;
69 	_ast_flt_unsigned_max_t	m;
70 
71 	static char		lx[] = "0123456789abcdef";
72 	static char		ux[] = "0123456789ABCDEF";
73 
74 	*sign = *decpt = 0;
75 
76 	if(isnanl(dv))
77 		return SF_NAN;
78 #if _lib_isinf
79 	if (n = isinf(dv))
80 	{	if (n < 0)
81 			*sign = 1;
82 		return SF_INF;
83 	}
84 #endif
85 #if !_ast_fltmax_double
86 	if(format&SFFMT_LDOUBLE)
87 	{	Sfdouble_t	f = dv;
88 #if _c99_in_the_wild
89 #if _lib_signbit
90 		if (signbit(f))
91 #else
92 #if _lib_copysignl
93 		if (copysignl(1.0, f) < 0.0)
94 #else
95 #if _lib_copysign
96 		if (copysign(1.0, (double)f) < 0.0)
97 #else
98 		if (f < 0.0)
99 #endif
100 #endif
101 #endif
102 		{	f = -f;
103 			*sign = 1;
104 		}
105 #if _lib_fpclassify
106 		switch (fpclassify(f))
107 		{
108 		case FP_INFINITE:
109 			return SF_INF;
110 		case FP_NAN:
111 			return SF_NAN;
112 		case FP_ZERO:
113 			return SF_ZERO;
114 		}
115 #endif
116 #else
117 		if (f < 0.0)
118 		{	f = -f;
119 			*sign = 1;
120 		}
121 #endif
122 		if(f < LDBL_MIN)
123 			return SF_ZERO;
124 		if(f > LDBL_MAX)
125 			return SF_INF;
126 
127 		if(format & SFFMT_AFORMAT)
128 		{	Sfdouble_t	g;
129 			int		x;
130 			b = sp = buf;
131 			ep = (format & SFFMT_UPPER) ? ux : lx;
132 			if(n_digit <= 0 || n_digit >= (size - 9))
133 				n_digit = size - 9;
134 			endsp = sp + n_digit + 1;
135 
136 			g = frexpl(f, &x);
137 			*decpt = x;
138 			f = ldexpl(g, 8 * sizeof(m) - 3);
139 
140 			for (;;)
141 			{	m = f;
142 				x = 8 * sizeof(m);
143 				while ((x -= 4) >= 0)
144 				{	*sp++ = ep[(m >> x) & 0xf];
145 					if (sp >= endsp)
146 					{	ep = sp + 1;
147 						goto done;
148 					}
149 				}
150 				f -= m;
151 				f = ldexpl(f, 8 * sizeof(m));
152 			}
153 		}
154 
155 		n = 0;
156 		if(f >= (Sfdouble_t)SF_MAXLONG)
157 		{	/* scale to a small enough number to fit an int */
158 			v = SF_MAXEXP10-1;
159 			do
160 			{	if(f < _Sfpos10[v])
161 					v -= 1;
162 				else
163 				{
164 					f *= _Sfneg10[v];
165 					if((n += (1<<v)) >= SF_IDIGITS)
166 						return SF_INF;
167 				}
168 			} while(f >= (Sfdouble_t)SF_MAXLONG);
169 		}
170 		*decpt = (int)n;
171 
172 		b = sp = buf + SF_INTPART;
173 		if((v = (long)f) != 0)
174 		{	/* translate the integer part */
175 			f -= (Sfdouble_t)v;
176 
177 			sfucvt(v,sp,n,ep,long,ulong);
178 
179 			n = b-sp;
180 			if((*decpt += (int)n) >= SF_IDIGITS)
181 				return SF_INF;
182 			b = sp;
183 			sp = buf + SF_INTPART;
184 		}
185 		else	n = 0;
186 
187 		/* remaining number of digits to compute; add 1 for later rounding */
188 		n = (((format&SFFMT_EFORMAT) || *decpt <= 0) ? 1 : *decpt+1) - n;
189 		if(n_digit > 0)
190 		{	if(n_digit > LDBL_DIG)
191 				n_digit = LDBL_DIG;
192 			n += n_digit;
193 		}
194 
195 		if((ep = (sp+n)) > (endsp = buf+(size-2)))
196 			ep = endsp;
197 		if(sp > ep)
198 			sp = ep;
199 		else
200 		{
201 			if((format&SFFMT_EFORMAT) && *decpt == 0 && f > 0.)
202 			{	Sfdouble_t	d;
203 				while((long)(d = f*10.) == 0)
204 				{	f = d;
205 					*decpt -= 1;
206 				}
207 			}
208 
209 			while(sp < ep)
210 			{	/* generate fractional digits */
211 				if(f <= 0.)
212 				{	/* fill with 0's */
213 					do { *sp++ = '0'; } while(sp < ep);
214 					goto done;
215 				}
216 				else if((n = (long)(f *= 10.)) < 10)
217 				{	*sp++ = '0' + n;
218 					f -= n;
219 				}
220 				else /* n == 10 */
221 				{	do { *sp++ = '9'; } while(sp < ep);
222 				}
223 			}
224 		}
225 	} else
226 #endif
227 	{	double	f = (double)dv;
228 
229 #if _lib_isinf
230 		if (n = isinf(f))
231 		{	if (n < 0)
232 				*sign = 1;
233 			return SF_INF;
234 		}
235 #endif
236 #if _c99_in_the_wild
237 #if _lib_signbit
238 		if (signbit(f))
239 #else
240 #if _lib_copysign
241 		if (copysign(1.0, f) < 0.0)
242 #else
243 		if (f < 0.0)
244 #endif
245 #endif
246 		{	f = -f;
247 			*sign = 1;
248 		}
249 #if _lib_fpclassify
250 		switch (fpclassify(f))
251 		{
252 		case FP_INFINITE:
253 			return SF_INF;
254 		case FP_NAN:
255 			return SF_NAN;
256 		case FP_ZERO:
257 			return SF_ZERO;
258 		}
259 #endif
260 #else
261 		if (f < 0.0)
262 		{	f = -f;
263 			*sign = 1;
264 		}
265 #endif
266 		if(f < DBL_MIN)
267 			return SF_ZERO;
268 		if(f > DBL_MAX)
269 			return SF_INF;
270 
271 		if(format & SFFMT_AFORMAT)
272 		{	double	g;
273 			int	x;
274 			b = sp = buf;
275 			ep = (format & SFFMT_UPPER) ? ux : lx;
276 			if(n_digit <= 0 || n_digit >= (size - 9))
277 				n_digit = size - 9;
278 			endsp = sp + n_digit;
279 
280 			g = frexp(f, &x);
281 			*decpt = x;
282 			f = ldexp(g, 8 * sizeof(m) - 3);
283 
284 			for (;;)
285 			{	m = f;
286 				x = 8 * sizeof(m);
287 				while ((x -= 4) >= 0)
288 				{	*sp++ = ep[(m >> x) & 0xf];
289 					if (sp >= endsp)
290 					{	ep = sp + 1;
291 						goto done;
292 					}
293 				}
294 				f -= m;
295 				f = ldexp(f, 8 * sizeof(m));
296 			}
297 		}
298 		n = 0;
299 		if(f >= (double)SF_MAXLONG)
300 		{	/* scale to a small enough number to fit an int */
301 			v = SF_MAXEXP10-1;
302 			do
303 			{	if(f < _Sfpos10[v])
304 					v -= 1;
305 				else
306 				{	f *= _Sfneg10[v];
307 					if((n += (1<<v)) >= SF_IDIGITS)
308 						return SF_INF;
309 				}
310 			} while(f >= (double)SF_MAXLONG);
311 		}
312 		*decpt = (int)n;
313 
314 		b = sp = buf + SF_INTPART;
315 		if((v = (long)f) != 0)
316 		{	/* translate the integer part */
317 			f -= (double)v;
318 
319 			sfucvt(v,sp,n,ep,long,ulong);
320 
321 			n = b-sp;
322 			if((*decpt += (int)n) >= SF_IDIGITS)
323 				return SF_INF;
324 			b = sp;
325 			sp = buf + SF_INTPART;
326 		}
327 		else	n = 0;
328 
329 		/* remaining number of digits to compute; add 1 for later rounding */
330 		n = (((format&SFFMT_EFORMAT) || *decpt <= 0) ? 1 : *decpt+1) - n;
331 		if(n_digit > 0)
332 		{	if(n_digit > DBL_DIG)
333 				n_digit = DBL_DIG;
334 			n += n_digit;
335 		}
336 
337 		if((ep = (sp+n)) > (endsp = buf+(size-2)))
338 			ep = endsp;
339 		if(sp > ep)
340 			sp = ep;
341 		else
342 		{
343 			if((format&SFFMT_EFORMAT) && *decpt == 0 && f > 0.)
344 			{	reg double	d;
345 				while((long)(d = f*10.) == 0)
346 				{	f = d;
347 					*decpt -= 1;
348 				}
349 			}
350 
351 			while(sp < ep)
352 			{	/* generate fractional digits */
353 				if(f <= 0.)
354 				{	/* fill with 0's */
355 					do { *sp++ = '0'; } while(sp < ep);
356 					goto done;
357 				}
358 				else if((n = (long)(f *= 10.)) < 10)
359 				{	*sp++ = (char)('0' + n);
360 					f -= n;
361 				}
362 				else /* n == 10 */
363 				{	do { *sp++ = '9'; } while(sp < ep);
364 				}
365 			}
366 		}
367 	}
368 
369 	if(ep <= b)
370 		ep = b+1;
371 	else if(ep < endsp)
372 	{	/* round the last digit */
373 		*--sp += 5;
374 		while(*sp > '9')
375 		{	*sp = '0';
376 			if(sp > b)
377 				*--sp += 1;
378 			else
379 			{	/* next power of 10 */
380 				*sp = '1';
381 				*decpt += 1;
382 				if(!(format&SFFMT_EFORMAT))
383 				{	/* add one more 0 for %f precision */
384 					ep[-1] = '0';
385 					ep += 1;
386 				}
387 			}
388 		}
389 	}
390 
391 done:
392 	*--ep = '\0';
393 	if(len)
394 		*len = ep-b;
395 	return b;
396 }
397