#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include "math.h"
#include "gpkieee754.h"
#include "gpkNaN.h"
#include "gpklib.h"

/* Returns NaN if the number isn't clean:
				e.g., "35x" will return NaN, while regular atof()
				will just return 35.0. */
double safe_atof(C char *s)
{
 if(!s)
	return quiet_nan(0);

 char *ep = 0;
 errno = 0;
 double t = strtod(s, &ep);
 while(ep && *ep)	{
	if(!isspace(*ep))
		return quiet_nan(0);
	ep++;
	}

 if(errno==ERANGE && t==0)
	errno = 0;
 else if(errno==ERANGE && t!=0)
	t = t>0 ? infinity() : -infinity();
 else if(errno != 0)
	return quiet_nan(0);

 return t;
}





/* Returns LONG_NaN if the number isn't clean:
				e.g., "35x" will return LONG_NaN, while regular atoi()
				will just return 35.   See myNaN.h .*/
long safe_atol(C char *s)
{
 if(!s)
	return LONG_NAN;

 char *ep = 0;
 errno = 0;
 long t = strtol(s, &ep, 10);
 if(errno == ERANGE && t == LONG_MAX)
	return LONG_Max;
 else if(errno==ERANGE && t==LONG_MIN)
	return LONG_Min;
 else if(errno != 0)
	return LONG_NAN;

 if(ep && *ep=='.')	{		/* Accepts 35.00 as an integer. */
	ep++;
	while(ep && *ep=='0')
		ep++;
	}
 while(ep && *ep)	{		/* Accepts '24   ' as a valid integer. */
	if(!isspace(*ep))
		return LONG_NAN;
	ep++;
	}


 return t;
}


int safe_atoi(C char *s)
{
 long t = safe_atol(s);
 if(t == LONG_NAN)
	return INT_NAN;
 else if(t!=(int)t && t > 0)
	return INT_Max;
 else if(t!=(int)t && t < 0)
	return INT_Min;
 return (int)t;
}



short safe_atoh(C char *s)
{
 long t = safe_atol(s);
 if(t == LONG_NAN)
	return SHRT_NAN;
 else if(t!=(int)t && t > 0)
	return SHRT_Max;
 else if(t!=(int)t && t < 0)
	return SHRT_Min;
 return (int)t;
}
