xref: /titanic_44/usr/src/lib/libast/common/sfio/sfcvt.c (revision 726fad2a65f16c200a03969c29cb5c86c2d427db)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2010 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, *t;
118 	int			x;
119 	_ast_flt_unsigned_max_t	m;
120 
121 	static char		lx[] = "0123456789abcdef";
122 	static char		ux[] = "0123456789ABCDEF";
123 
124 	*sign = *decpt = 0;
125 
126 #if !_ast_fltmax_double
127 	if(format&SFFMT_LDOUBLE)
128 	{	Sfdouble_t	f = *(Sfdouble_t*)vp;
129 
130 		if(isnanl(f))
131 		{
132 #if _lib_signbit
133 			if (signbit(f))
134 #else
135 			if (f < 0)
136 #endif
137 				*sign = 1;
138 			return SF_NAN;
139 		}
140 #if _lib_isinf
141 		if (n = isinf(f))
142 		{
143 #if _lib_signbit
144 			if (signbit(f))
145 #else
146 			if (n < 0 || f < 0)
147 #endif
148 				*sign = 1;
149 			return SF_INF;
150 		}
151 #endif
152 # if _c99_in_the_wild
153 #  if _lib_signbit
154 		if (signbit(f))
155 #  else
156 #   if _lib_copysignl
157 		if (copysignl(1.0, f) < 0.0)
158 #   else
159 #    if _lib_copysign
160 		if (copysign(1.0, (double)f) < 0.0)
161 #    else
162 		if (f < 0.0)
163 #    endif
164 #   endif
165 #  endif
166 		{	f = -f;
167 			*sign = 1;
168 		}
169 #  if _lib_fpclassify
170 		switch (fpclassify(f))
171 		{
172 		case FP_INFINITE:
173 			return SF_INF;
174 		case FP_NAN:
175 			return SF_NAN;
176 		case FP_ZERO:
177 			return SF_ZERO;
178 		}
179 #  endif
180 # else
181 #  if _lib_signbit
182 		if (signbit(f))
183 #  else
184 		if (f < 0.0 || f == 0.0 && neg0ld(f))
185 #  endif
186 		{	f = -f;
187 			*sign = 1;
188 		}
189 # endif
190 		if(f < LDBL_MIN)
191 			return SF_ZERO;
192 		if(f > LDBL_MAX)
193 			return SF_INF;
194 
195 		if(format & SFFMT_AFORMAT)
196 		{	Sfdouble_t	g;
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 						goto around;
214 				}
215 				f -= m;
216 				f = ldexpl(f, 8 * sizeof(m));
217 			}
218 		}
219 
220 		n = 0;
221 		if(f >= (Sfdouble_t)CVT_LDBL_MAXINT)
222 		{	/* scale to a small enough number to fit an int */
223 			v = SF_MAXEXP10-1;
224 			do
225 			{	if(f < _Sfpos10[v])
226 					v -= 1;
227 				else
228 				{
229 					f *= _Sfneg10[v];
230 					if((n += (1<<v)) >= SF_IDIGITS)
231 						return SF_INF;
232 				}
233 			} while(f >= (Sfdouble_t)CVT_LDBL_MAXINT);
234 		}
235 		else if(f > 0.0 && f < 0.1)
236 		{	/* scale to avoid excessive multiply by 10 below */
237 			v = SF_MAXEXP10-1;
238 			do
239 			{	if(f <= _Sfneg10[v])
240 				{	f *= _Sfpos10[v];
241 					if((n += (1<<v)) >= SF_IDIGITS)
242 						return SF_INF;
243 				}
244 				else if (--v < 0)
245 					break;
246 			} while(f < 0.1);
247 			n = -n;
248 		}
249 		*decpt = (int)n;
250 
251 		b = sp = buf + SF_INTPART;
252 		if((v = (CVT_LDBL_INT)f) != 0)
253 		{	/* translate the integer part */
254 			f -= (Sfdouble_t)v;
255 
256 			sfucvt(v,sp,n,ep,CVT_LDBL_INT,unsigned CVT_LDBL_INT);
257 
258 			n = b-sp;
259 			if((*decpt += (int)n) >= SF_IDIGITS)
260 				return SF_INF;
261 			b = sp;
262 			sp = buf + SF_INTPART;
263 		}
264 		else	n = 0;
265 
266 		/* remaining number of digits to compute; add 1 for later rounding */
267 		n = (((format&SFFMT_EFORMAT) || *decpt <= 0) ? 1 : *decpt+1) - n;
268 		if(n_digit > 0)
269 		{	if(n_digit > LDBL_DIG)
270 				n_digit = LDBL_DIG;
271 			n += n_digit;
272 		}
273 
274 		if((ep = (sp+n)) > (endsp = buf+(size-2)))
275 			ep = endsp;
276 		if(sp > ep)
277 			sp = ep;
278 		else
279 		{
280 			if((format&SFFMT_EFORMAT) && *decpt == 0 && f > 0.)
281 			{	Sfdouble_t	d;
282 				while((long)(d = f*10.) == 0)
283 				{	f = d;
284 					*decpt -= 1;
285 				}
286 			}
287 
288 			while(sp < ep)
289 			{	/* generate fractional digits */
290 				if(f <= 0.)
291 				{	/* fill with 0's */
292 					do { *sp++ = '0'; } while(sp < ep);
293 					goto done;
294 				}
295 				else if((n = (long)(f *= 10.)) < 10)
296 				{	*sp++ = '0' + n;
297 					f -= n;
298 				}
299 				else /* n == 10 */
300 				{	do { *sp++ = '9'; } while(sp < ep);
301 				}
302 			}
303 		}
304 	} else
305 #endif
306 	{	double	f = *(double*)vp;
307 
308 		if(isnan(f))
309 		{
310 #if _lib_signbit
311 			if (signbit(f))
312 #else
313 			if (f < 0)
314 #endif
315 				*sign = 1;
316 			return SF_NAN;
317 		}
318 #if _lib_isinf
319 		if (n = isinf(f))
320 		{
321 #if _lib_signbit
322 			if (signbit(f))
323 #else
324 			if (n < 0 || f < 0)
325 #endif
326 				*sign = 1;
327 			return SF_INF;
328 		}
329 #endif
330 #if _c99_in_the_wild
331 # if _lib_signbit
332 		if (signbit(f))
333 # else
334 #  if _lib_copysign
335 		if (copysign(1.0, f) < 0.0)
336 #  else
337 		if (f < 0.0)
338 #  endif
339 # endif
340 		{	f = -f;
341 			*sign = 1;
342 		}
343 # if _lib_fpclassify
344 		switch (fpclassify(f))
345 		{
346 		case FP_INFINITE:
347 			return SF_INF;
348 		case FP_NAN:
349 			return SF_NAN;
350 		case FP_ZERO:
351 			return SF_ZERO;
352 		}
353 # endif
354 #else
355 # if _lib_signbit
356 		if (signbit(f))
357 # else
358 		if (f < 0.0 || f == 0.0 && neg0d(f))
359 # endif
360 		{	f = -f;
361 			*sign = 1;
362 		}
363 #endif
364 		if(f < DBL_MIN)
365 			return SF_ZERO;
366 		if(f > DBL_MAX)
367 			return SF_INF;
368 
369 		if(format & SFFMT_AFORMAT)
370 		{	double		g;
371 			b = sp = buf;
372 			ep = (format & SFFMT_UPPER) ? ux : lx;
373 			if(n_digit <= 0 || n_digit >= (size - 9))
374 				n_digit = size - 9;
375 			endsp = sp + n_digit + 1;
376 
377 			g = frexp(f, &x);
378 			*decpt = x;
379 			f = ldexp(g, 8 * sizeof(m) - 3);
380 
381 			for (;;)
382 			{	m = f;
383 				x = 8 * sizeof(m);
384 				while ((x -= 4) >= 0)
385 				{	*sp++ = ep[(m >> x) & 0xf];
386 					if (sp >= endsp)
387 						goto around;
388 				}
389 				f -= m;
390 				f = ldexp(f, 8 * sizeof(m));
391 			}
392 		}
393 		n = 0;
394 		if(f >= (double)CVT_DBL_MAXINT)
395 		{	/* scale to a small enough number to fit an int */
396 			v = SF_MAXEXP10-1;
397 			do
398 			{	if(f < _Sfpos10[v])
399 					v -= 1;
400 				else
401 				{	f *= _Sfneg10[v];
402 					if((n += (1<<v)) >= SF_IDIGITS)
403 						return SF_INF;
404 				}
405 			} while(f >= (double)CVT_DBL_MAXINT);
406 		}
407 		else if(f > 0.0 && f < 1e-8)
408 		{	/* scale to avoid excessive multiply by 10 below */
409 			v = SF_MAXEXP10-1;
410 			do
411 			{	if(f <= _Sfneg10[v])
412 				{	f *= _Sfpos10[v];
413 					if((n += (1<<v)) >= SF_IDIGITS)
414 						return SF_INF;
415 				}
416 				else if(--v < 0)
417 					break;
418 			} while(f < 0.1);
419 			n = -n;
420 		}
421 		*decpt = (int)n;
422 
423 		b = sp = buf + SF_INTPART;
424 		if((v = (CVT_DBL_INT)f) != 0)
425 		{	/* translate the integer part */
426 			f -= (double)v;
427 
428 			sfucvt(v,sp,n,ep,CVT_DBL_INT,unsigned CVT_DBL_INT);
429 
430 			n = b-sp;
431 			if((*decpt += (int)n) >= SF_IDIGITS)
432 				return SF_INF;
433 			b = sp;
434 			sp = buf + SF_INTPART;
435 		}
436 		else	n = 0;
437 
438 		/* remaining number of digits to compute; add 1 for later rounding */
439 		n = (((format&SFFMT_EFORMAT) || *decpt <= 0) ? 1 : *decpt+1) - n;
440 		if(n_digit > 0)
441 		{	if(n_digit > DBL_DIG)
442 				n_digit = DBL_DIG;
443 			n += n_digit;
444 		}
445 
446 		if((ep = (sp+n)) > (endsp = buf+(size-2)))
447 			ep = endsp;
448 		if(sp > ep)
449 			sp = ep;
450 		else
451 		{
452 			if((format&SFFMT_EFORMAT) && *decpt == 0 && f > 0.)
453 			{	reg double	d;
454 				while((long)(d = f*10.) == 0)
455 				{	f = d;
456 					*decpt -= 1;
457 				}
458 			}
459 
460 			while(sp < ep)
461 			{	/* generate fractional digits */
462 				if(f <= 0.)
463 				{	/* fill with 0's */
464 					do { *sp++ = '0'; } while(sp < ep);
465 					goto done;
466 				}
467 				else if((n = (long)(f *= 10.)) < 10)
468 				{	*sp++ = (char)('0' + n);
469 					f -= n;
470 				}
471 				else /* n == 10 */
472 				{	do { *sp++ = '9'; } while(sp < ep);
473 					break;
474 				}
475 			}
476 		}
477 	}
478 
479 	if(ep <= b)
480 		ep = b+1;
481 	else if(ep < endsp)
482 	{	/* round the last digit */
483 		*--sp += 5;
484 		while(*sp > '9')
485 		{	*sp = '0';
486 			if(sp > b)
487 				*--sp += 1;
488 			else
489 			{	/* next power of 10 */
490 				*sp = '1';
491 				*decpt += 1;
492 				if(!(format&SFFMT_EFORMAT))
493 				{	/* add one more 0 for %f precision */
494 					ep[-1] = '0';
495 					ep += 1;
496 				}
497 			}
498 		}
499 	}
500 
501  done:
502 	*--ep = '\0';
503 	if(len)
504 		*len = ep-b;
505 	return b;
506  around:
507 	if (((m >> x) & 0xf) >= 8)
508 	{	t = sp - 1;
509 		for (;;)
510 		{	if (--t <= b)
511 			{	(*decpt)++;
512 				break;
513 			}
514 			switch (*t)
515 			{
516 			case 'f':
517 			case 'F':
518 				*t = '0';
519 				continue;
520 			case '9':
521 				*t = ep[10];
522 				break;
523 			default:
524 				(*t)++;
525 				break;
526 			}
527 			break;
528 		}
529 	}
530 	ep = sp + 1;
531 	goto done;
532 }
533