
/********************************************
mawk_matherr.c

libmawk changes (C) 2009-2010, Tibor 'Igor2' Palinkas;
based on mawk code coming with the below copyright:

copyright 1991, Michael D. Brennan

This is a source file for mawk, an implementation of
the AWK programming language.

Mawk is distributed without warranty under the terms of
the GNU General Public License, version 2, 1991.
********************************************/
#include  "mawk.h"
#include  "num.h"

struct exception {
	int dummy;
};

/* Sets up NetBSD 1.0A for ieee floating point */
#if defined(_LIB_VERSION_TYPE) && defined(_LIB_VERSION) && defined(_IEEE_)
_LIB_VERSION_TYPE _LIB_VERSION = _IEEE_;
#endif

#ifdef	USE_IEEEFP_H
#include <ieeefp.h>
#endif

#ifndef	 TURN_OFF_FPE_TRAPS
#define	 TURN_OFF_FPE_TRAPS()		/* nothing */
#endif

#ifndef	 TURN_ON_FPE_TRAPS
#define	 TURN_ON_FPE_TRAPS()		/* nothing */
#endif

#ifdef  SV_SIGINFO
#include <siginfo.h>
#define  FPE_ZERODIVIDE  FPE_FLTDIV
#define  FPE_OVERFLOW    FPE_FLTOVF
#endif

#ifdef	 FPE_TRAPS_ON
#include <signal.h>

/* machine dependent changes might be needed here */

#ifdef   SV_SIGINFO
static void fpe_catch(int signal, siginfo_t *sip)
{
	int why = sip->si_code;

#else

static void fpe_catch(int signal, int why)
{
#endif /* SV_SIGINFO  */

#if   NOINFO_SIGFPE
	mawk_rt_error("floating point exception, probably mawk_overflow");
	/* does not return */
#else

	switch (why) {
	case FPE_ZERODIVIDE:
		mawk_rt_error("division by zero");

	case FPE_OVERFLOW:
		mawk_rt_error("floating point mawk_overflow");

	default:
		mawk_rt_error("floating point exception");
	}
#endif /* noinfo_sigfpe */
}

void mawk_fpe_init(void)
{
	return;
	TURN_ON_FPE_TRAPS();

#ifndef  SV_SIGINFO
	signal(SIGFPE, fpe_catch);

#else
	{
		struct sigaction x;

		memset(&x, 0, sizeof(x));
		x.sa_handler = fpe_catch;
		x.sa_flags = SA_SIGINFO;

		sigaction(SIGFPE, &x, (struct sigaction *) 0);
	}
#endif

#ifdef  HAVE_STRTOD_OVF_BUG
	/* we've already turned the traps on */
	working_mask = fpgetmask();
	MAWK->entry_mask = working_mask & ~FP_X_DZ & ~FP_X_OFL;
#endif
}

#else	/* FPE_TRAPS not defined */

void mawk_fpe_init(void)
{
	return;
	TURN_OFF_FPE_TRAPS();
}
#endif

#ifndef	 NO_MATHERR

#ifndef	 FPE_TRAPS_ON

/* If we are not trapping math errors, we will shutup the library calls
*/

int mawk_matherr(struct exception *e)
{
	return 1;
}

#else	/* print error message and exit */

int mawk_matherr(struct exception *e)
{
	char *error;

	switch (e->type) {
	case DOMAIN:
	case SING:
		error = "domain error";
		break;

	case OVERFLOW:
		error = "mawk_overflow";
		break;

	case TLOSS:
	case PLOSS:
		error = "loss of significance";
		break;

	case UNDERFLOW:
		e->retval = MAWK_NUM_ZERO;
		return 1;										/* ignore it */
	}

	if (strcmp(e->name, "atan2") == 0)
		mawk_rt_error("atan2(%g,%g) : %s", e->arg1, e->arg2, error);
	else
		mawk_rt_error("%s(%g) : %s", e->name, e->arg1, error);

	/* won't get here */
	return 0;
}
#endif /* FPE_TRAPS_ON */

#endif /*  ! no mawk_matherr */


/* this is how one gets the libm calls to do the right
thing on bsd43_vax */

#ifdef	 BSD43_VAX

#include <errno.h>

double infnan(int arg)
{
	switch (arg) {
	case ERANGE:
		errno = ERANGE;
		return HUGE;
	case -ERANGE:
		errno = EDOM;
		return -HUGE;
	default:
		errno = EDOM;
	}
	return MAWK_NUM_ZERO;
}

#endif /* BSD43_VAX */

/* This routine is for XENIX-68K 2.3A.
    Error check routine to be called after fp arithmetic.
*/

#if SW_FP_CHECK
/* Definitions of bit values in iserr() return value */

#define OVFLOW		2
#define UFLOW		4
#define ZERODIV		8
#define OVFLFIX		32
#define INFNAN		64

void fpcheck(void)
{
	register int fperrval;
	char *errdesc;

	if ((fperrval = iserr()) == 0)
		return;											/* no error */

	errdesc = (char *) 0;

	if (fperrval & INFNAN)
		errdesc = "arg is infinity or NAN";
	else if (fperrval & ZERODIV)
		errdesc = "division by zero";
	else if (fperrval & OVFLOW)
		errdesc = "mawk_overflow";
	else if (fperrval & UFLOW);		/* ignored */

	if (errdesc)
		mawk_rt_error("%s", errdesc);
}

#endif

#ifdef HAVE_STRTOD_OVF_BUG
/* buggy strtod in solaris, probably any sysv with ieee754
   strtod can generate an fpe  */

double strtod_with_ovf_bug(const char *s, char **ep)
{
	double ret;

	fpsetmask(MAWK->entry_mask);	/* traps off */
#undef strtod										/* make real strtod visible */
	ret = strtod(s, ep);
	fpsetmask(working_mask);			/* traps on */
	return ret;
}
#endif
