212 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			212 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * fltpr.c - print floating point numbers
 | |
|  */
 | |
| /* $Id$ */
 | |
| 
 | |
| #include <string.h>
 | |
| #include <stdarg.h>
 | |
| #include "loc_incl.h"
 | |
| 
 | |
| #if ACKCONF_WANT_STDIO && ACKCONF_WANT_STDIO_FLOAT
 | |
| 
 | |
| static char*
 | |
| _pfloat(long double r, register char* s, int n, int flags)
 | |
| {
 | |
| 	register char* s1;
 | |
| 	int sign, dp;
 | |
| 	register int i;
 | |
| 
 | |
| 	s1 = _fcvt(r, n, &dp, &sign);
 | |
| 	if (sign)
 | |
| 		*s++ = '-';
 | |
| 	else if (flags & FL_SIGN)
 | |
| 		*s++ = '+';
 | |
| 	else if (flags & FL_SPACE)
 | |
| 		*s++ = ' ';
 | |
| 
 | |
| 	if (dp <= 0)
 | |
| 		*s++ = '0';
 | |
| 	for (i = dp; i > 0; i--)
 | |
| 		if (*s1)
 | |
| 			*s++ = *s1++;
 | |
| 		else
 | |
| 			*s++ = '0';
 | |
| 	if (((i = n) > 0) || (flags & FL_ALT))
 | |
| 		*s++ = '.';
 | |
| 	while (++dp <= 0)
 | |
| 	{
 | |
| 		if (--i < 0)
 | |
| 			break;
 | |
| 		*s++ = '0';
 | |
| 	}
 | |
| 	while (--i >= 0)
 | |
| 		if (*s1)
 | |
| 			*s++ = *s1++;
 | |
| 		else
 | |
| 			*s++ = '0';
 | |
| 	return s;
 | |
| }
 | |
| 
 | |
| static char*
 | |
| _pscien(long double r, register char* s, int n, int flags)
 | |
| {
 | |
| 	int sign, dp;
 | |
| 	register char* s1;
 | |
| 
 | |
| 	s1 = _ecvt(r, n + 1, &dp, &sign);
 | |
| 	if (sign)
 | |
| 		*s++ = '-';
 | |
| 	else if (flags & FL_SIGN)
 | |
| 		*s++ = '+';
 | |
| 	else if (flags & FL_SPACE)
 | |
| 		*s++ = ' ';
 | |
| 
 | |
| 	*s++ = *s1++;
 | |
| 	if ((n > 0) || (flags & FL_ALT))
 | |
| 		*s++ = '.';
 | |
| 	while (--n >= 0)
 | |
| 		if (*s1)
 | |
| 			*s++ = *s1++;
 | |
| 		else
 | |
| 			*s++ = '0';
 | |
| 	*s++ = 'e';
 | |
| 	if (r != 0)
 | |
| 		--dp;
 | |
| 	if (dp < 0)
 | |
| 	{
 | |
| 		*s++ = '-';
 | |
| 		dp = -dp;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		*s++ = '+';
 | |
| 	}
 | |
| 	if (dp >= 100)
 | |
| 	{
 | |
| 		*s++ = '0' + (dp / 100);
 | |
| 		dp %= 100;
 | |
| 	}
 | |
| 	*s++ = '0' + (dp / 10);
 | |
| 	*s++ = '0' + (dp % 10);
 | |
| 	return s;
 | |
| }
 | |
| 
 | |
| #define NDIGINEXP(exp) (((exp) >= 100 || (exp) <= -100) ? 3 : 2)
 | |
| #define LOW_EXP -4
 | |
| #define USE_EXP(exp, ndigits) (((exp) < LOW_EXP + 1) || (exp >= ndigits + 1))
 | |
| 
 | |
| static char*
 | |
| _gcvt(long double value, int ndigit, char* s, int flags)
 | |
| {
 | |
| 	int sign, dp;
 | |
| 	register char *s1, *s2;
 | |
| 	register int i;
 | |
| 	register int nndigit = ndigit;
 | |
| 
 | |
| 	s1 = _ecvt(value, ndigit, &dp, &sign);
 | |
| 	s2 = s;
 | |
| 	if (sign)
 | |
| 		*s2++ = '-';
 | |
| 	else if (flags & FL_SIGN)
 | |
| 		*s2++ = '+';
 | |
| 	else if (flags & FL_SPACE)
 | |
| 		*s2++ = ' ';
 | |
| 
 | |
| 	if (!(flags & FL_ALT))
 | |
| 		for (i = nndigit - 1; i > 0 && s1[i] == '0'; i--)
 | |
| 			nndigit--;
 | |
| 
 | |
| 	if (USE_EXP(dp, ndigit))
 | |
| 	{
 | |
| 		/* Use E format */
 | |
| 		dp--;
 | |
| 		*s2++ = *s1++;
 | |
| 		if ((nndigit > 1) || (flags & FL_ALT))
 | |
| 			*s2++ = '.';
 | |
| 		while (--nndigit > 0)
 | |
| 			*s2++ = *s1++;
 | |
| 		*s2++ = 'e';
 | |
| 		if (dp < 0)
 | |
| 		{
 | |
| 			*s2++ = '-';
 | |
| 			dp = -dp;
 | |
| 		}
 | |
| 		else
 | |
| 			*s2++ = '+';
 | |
| 		s2 += NDIGINEXP(dp);
 | |
| 		*s2 = 0;
 | |
| 		for (i = NDIGINEXP(dp); i > 0; i--)
 | |
| 		{
 | |
| 			*--s2 = dp % 10 + '0';
 | |
| 			dp /= 10;
 | |
| 		}
 | |
| 		return s;
 | |
| 	}
 | |
| 	/* Use f format */
 | |
| 	if (dp <= 0)
 | |
| 	{
 | |
| 		if (*s1 != '0')
 | |
| 		{
 | |
| 			/* otherwise the whole number is 0 */
 | |
| 			*s2++ = '0';
 | |
| 			*s2++ = '.';
 | |
| 		}
 | |
| 		while (dp < 0)
 | |
| 		{
 | |
| 			dp++;
 | |
| 			*s2++ = '0';
 | |
| 		}
 | |
| 	}
 | |
| 	for (i = 1; i <= nndigit; i++)
 | |
| 	{
 | |
| 		*s2++ = *s1++;
 | |
| 		if (i == dp)
 | |
| 			*s2++ = '.';
 | |
| 	}
 | |
| 	if (i <= dp)
 | |
| 	{
 | |
| 		while (i++ <= dp)
 | |
| 			*s2++ = '0';
 | |
| 		*s2++ = '.';
 | |
| 	}
 | |
| 	if ((s2[-1] == '.') && !(flags & FL_ALT))
 | |
| 		s2--;
 | |
| 	*s2 = '\0';
 | |
| 	return s;
 | |
| }
 | |
| 
 | |
| char* _f_print(va_list* ap, int flags, char* s, char c, int precision)
 | |
| {
 | |
| 	register char* old_s = s;
 | |
| 	long double ld_val;
 | |
| 
 | |
| 	if (flags & FL_LONGDOUBLE)
 | |
| 		ld_val = va_arg(*ap, long double);
 | |
| 	else
 | |
| 		ld_val = (long double)va_arg(*ap, double);
 | |
| 
 | |
| 	switch (c)
 | |
| 	{
 | |
| 		case 'f':
 | |
| 			s = _pfloat(ld_val, s, precision, flags);
 | |
| 			break;
 | |
| 		case 'e':
 | |
| 		case 'E':
 | |
| 			s = _pscien(ld_val, s, precision, flags);
 | |
| 			break;
 | |
| 		case 'g':
 | |
| 		case 'G':
 | |
| 			s = _gcvt(ld_val, precision, s, flags);
 | |
| 			s += strlen(s);
 | |
| 			break;
 | |
| 	}
 | |
| 	if (c == 'E' || c == 'G')
 | |
| 	{
 | |
| 		while (*old_s && *old_s != 'e')
 | |
| 			old_s++;
 | |
| 		if (*old_s == 'e')
 | |
| 			*old_s = 'E';
 | |
| 	}
 | |
| 	return s;
 | |
| }
 | |
| #endif
 |