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