/* DEC	*ConvAsciiToDecimalRound(dst,src1,nid)
 *
 * ARGUMENT
 *	dst is a pointer to the	destination DEC	structure.
 *	src1 is	a ptr to the ascii string to be	converted.
 *
 * DESCRIPTION
 *	Converts an ascii string to an internal	format number
 *   and puts it into the dst DEC structure.  The number is rounded
 *   to	nid decimal places.
 *
 * SIDE	EFFECTS
 *	None. The destination structure	is indeterminate if
 *   an	overflow of significant	digits occured during conversion.
 *
 * RETURNS
 *	Returns	a pointer to the dest structure	unless overflow.
 *   Otherwise,	returns	a GM_NULL(a C false). On error,	the error
 *   is	in wGMError, unless an error was already there.
 *   Note that truncation of insignificant digits is not fatal,	but
 *   sets a warning flag for the caller	to determine if	that is	fatal
 *   for their application.
 *
 * POSSIBLE ERROR CODES
 *
 *	GM_NULLSTRING
 *	GM_NAN
 *	GM_CNVRE
 *	GM_CNVRW
 *	GM_INVALIDID
 *
 * AUTHOR
 *  Andy Anderson   13-JAN-1987	 14:30
 *   Copyright (C) 1987-1990 Greenleaf Software	Inc.  All rights reserved.
 *
 * MODIFICATIONS
 *
 *  Mark Nelson	  23-Jan-1990
 *   Modified to handle	leading	and trailing whitespace, like atoi();
 */

#include <stdio.h>
#include "gm.h"
#include "gmsystem.h"

DEC	*ConvAsciiToDecimalRound(dst, s, nid )
DEC	*dst;
char	*s;
int	nid;
{
	DEC	dx, *x=&dx;
	int	digright;
	int	sign, k, j, exp, expisn=0, equid, xtra=0;
	mbool	trwarn=FALSE;
	unsigned c10;
	register int	i, fd;

	_MacStart(GM_ATODR);
	fd = 0;
	sign = 1;	/* assume a positive sign */

/* If he hands us a null string, _MacRet error to user */
	if (!s)	{
		_MacErr(GM_NULLSTRING);
		_MacRet(GM_NULL); }

/* check for valid nid */
	if ((nid < GM_MINID) ||	(nid > GM_MAXID))  {
		_MacErr(GM_INVALIDID);
		_MacRet(GM_NULL);
	}

/* handle null pointers	*/
	if (!dst)  {
		_MacErr(GM_NULLPOINTER);
		_MacRet(GM_NULL);
	}

/* First strip any leading whitespace  */

	for (; s[fd] ==	' ' || s[fd] ==	'\t' ; fd++ ) ;

/* Then	check for an empty string */

	if (s[fd] == '\0')  {
		_MacErr(GM_NULLSTRING);
		_MacRet(GM_NULL);
		}

/* fix sign */
	for (; ((s[fd] == '-') || (s[fd] == '+')); fd++) {
		if (s[fd] == '-')
			sign = -1;
	}


/*  Strip leading zeroes from the string */
	while (	s[fd] == '0' )
	    fd++;

/*  Search for 'e' or 'E' signifying scientfic notation	*/
	for ( j	= fd; ;	j++ ) {
	    if ( s[j] == '\0' )
		break;
	    if ( s[j] == 'e' )
		break;
	    if ( s[j] == 'E' )
		break;
	    if ( s[j] == ' ' )
		break;
	    if ( s[j] == '\t' )
		break;
	}

/*  If there is	an exponent, calculate it or _MacRet GM_NAN */
	exp = 0;
	if ((s[j] == 'e' || s[j] == 'E')) {
		k=j+1;
		if ((s[k]=='+')	|| (s[k]=='-'))	 {
			expisn = (s[k]=='-') ? 1 : 0;
			k++;
		}
		do  {
			if ((s[k]<'0') || (s[k]>'9'))  {
				_MacErr(GM_NAN);
				_MacRet	(GM_NULL);
			}
			exp = 10*exp + s[k] - 0x30;
			k++;
		}  while (s[k] != 0 && s[k] != ' ' && s[k] != '\t' );
		if (expisn)
			exp = -exp;
	}

/*  check for bad characters */
	for (i=fd; i<j;	i++)
		if (((s[i] < '0') || (s[i] > '9')) && (s[i] != '.')
			&& (s[i] != ',')) {
			_MacErr(GM_NAN);
			_MacRet	(GM_NULL);
		}

/* set equal to	0 */
	_MacDZero(x);
	x->dc.id = 0;

	if (fd == j)  {
		_MacDCopy(dst, x);
		_MacRet(dst);
	}

/* everything else */
	digright = 0;

/* digits before decimal point */
	for (i=fd; (i<j	 ); i++)  {
		if ((s[i] >= '0') && (s[i] <= '9'))  {
			c10=s[i] - 0x30;
			if (x->dc.sl[3]	< 3276L)
				(void) _MulUnsArrP10AndAddInt(
					 x->dc.sl, c10);
			else  {
				if((s[i] >= '5') && wfGMRound)
					 /* round off */
					(void) _IncrementUnsArr(
						 x->dc.sl);
				for (; ((s[i]!='.') && (i<j)); i++)
					xtra++;
				if (xtra+exp>0)	 {
					_MacErr(GM_CNVRE);
					_MacRet(GM_NULL);
				}
				i=j;
				trwarn=TRUE;
				break;
			}
		}
		if (s[i] == '.') {
			i++;
			break;
		}
	}

/* digits after	decimal	point */
	for (; i<j; i++) {
		if ((s[i] >= '0') && (s[i] <= '9'))  {
		/* after decimal point */
			if ((digright-exp<nid)&&(x->dc.sl[3]<3276L)) {
			/* room	for digit */
				c10=s[i] - 0x30;
				(void) _MulUnsArrP10AndAddInt(
					 x->dc.sl, c10);
				digright++;
			}
			else {
			/* no room for digit */
				if((s[i] >= '5') && wfGMRound) {
					 /* round off */
					(void) _IncrementUnsArr(
						 x->dc.sl);
				}
				trwarn = TRUE;
				break;
			}
		}
		if (s[i] == '.')  {
			/* two decimal points */
			_MacErr(GM_NAN);
			_MacRet	(GM_NULL);
		}
	}

/* adjust for exponential */
	equid =	digright-xtra-exp;
	x->ls.lid=nid;

	if (equid>nid)	{
		trwarn=TRUE;
		if (!_MacIsDecZ(x))  {
			if (wfGMRound)
				_DivUnsArrByPwrOf10( x->dc.sl,
					5, equid-nid);
			else
				_DivUnsArrByPwrOf10Trunc( x->dc.sl,
					5, equid-nid);
			if (_MacIsDecZ(x))  {
				_MacErr(GM_CNVRE);
			}
		}
	}

	if (equid<nid)	{
		k=_MulUnsArrByPwrOf10( x->dc.sl, nid-equid, 5);
		if ((k!=GM_SUCCESS) || (x->dc.msd!=0)
			|| (x->dc.sl[3]	> 32767L))  {
			_MacErr(GM_CNVRE);
			_MacRet(GM_NULL);
		}
	}

/* adjust for sign */
	if (sign == -1)
		_MacDChgs(x);

	_MacDCopy(dst, x);

	if (trwarn)
		_MacErr(GM_CNVRW);

	_MacRet(dst);

}