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