Metropoli BBS
VIEWER: matherr.c MODE: TEXT (ASCII)
/*****************************************************************************
* Module to handle floating point errors:				     *
* Action taken in floating point error is set via the Action selected during *
* set up (see MathErr.h for different possible actions).		     *
*									     *
* This file is compiled under MSDOS only.				     *
*									     *
* Written by:  Gershon Elber			IBM PC Ver 1.0,	Mar. 1989    *
*****************************************************************************/

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <float.h>
#include <signal.h>
#include <setjmp.h>
#include <graphics.h>
#include "matherr.h"
#include "program.h"
#include "graphgen.h"

#ifndef TRUE
#define TRUE	-1
#define FALSE	0
#endif TRUE

static char *MathError = NULL;
static int MEAction = ME_IGNORE;
static void far *MEAddr = NULL;

static void PerformMEAction(void);
static void cdecl DefaultFPEHandler(int Sig, int Type, int *RegList);

/*****************************************************************************
*   Routine to set up the math error traping routines:			     *
* 1. redefine matherr routine, so it traps the floating points transadental  *
*    functions (sin, cos, log etc.).					     *
* 2. Traps and SIGFPE signals into our handler (traps lower level errors     *
*    such as div by zero).						     *
*****************************************************************************/
void MathErrorSetUp(int Action, void far *Addr)
{
    signal(SIGFPE, DefaultFPEHandler);	 /* Will trap floating point errors. */
    MEAction = Action;
    MEAddr = Addr;
}

/*****************************************************************************
*   Routine to fetch last math error if was was or NULL otherwise and reset  *
* it to the next time...						     *
*****************************************************************************/
char *MathErrorGet(void)
{
    char *p;

    p = MathError;
    MathError = NULL;
    return p;
}

/*****************************************************************************
*   Routine to kill current process after closing all open devices and	     *
* printing exact math error causing this death.				     *
*****************************************************************************/
static void PerformMEAction(void)
{
    void (far *PFunc)();

    switch (MEAction) {
	case ME_KILL:
#	    ifdef HAS_GRAPHICS
		GGCloseGraph();			/* Close the graphic driver. */
#	    endif HAS_GRAPHICS
	    fprintf(stderr, "Fatal Math Error - %s\n", MathError);
	    MyExit(1);
	    break;
	case ME_IGNORE:
	    break;
	case ME_LONGJMP:
	    longjmp(*(((jmp_buf *) MEAddr)), 1);
	    break;
	case ME_CALL:
	    PFunc = MEAddr;
	    (PFunc)();
	    break;
    }
}

/*****************************************************************************
*   Routine that is called from the floating point package in case of fatal  *
* floating point error. Print error message, long jump to main loop. Default *
* FPE handler - must be reset after redirected to other module.		     *
*****************************************************************************/
static void cdecl DefaultFPEHandler(int Sig, int Type, int *RegList)
{
    switch (Type) {
	case FPE_INTOVFLOW:
	    MathError = "integer overflow";
	    break;
	case FPE_INTDIV0:
	    MathError = "integer divide by zero";
	    break;
	case FPE_INVALID:
	    MathError = "invalid operation";
	    break;
	case FPE_ZERODIVIDE:
	    MathError = "division by zero";
	    break;
	case FPE_OVERFLOW:
	    MathError = "numeric overflow";
	    break;
	case FPE_UNDERFLOW:
	    MathError = "numeric underflow";
	    break;
	case FPE_INEXACT:
	    MathError = "precision lost";
	    break;
	case FPE_EXPLICITGEN:
	    MathError = "explicit signal";
	    break;
    }
    PerformMEAction();
}

/*****************************************************************************
* Routine to trap math errors -	set GlobalMathError to error number, and     *
* GlobalMathFunc to the	math function with the error. Return TRUE to	     *
* make it believe that everything is ok. now...				     *
*****************************************************************************/
int cdecl matherr(struct exception _FAR *except)
{
    static char s[32];

    except -> retval = 1.0;		   /* return something reasonable... */

    switch(except -> type) {
	case DOMAIN:
	    strcpy(s, "DOMAIN ");
	    break;
	case SING:
	    strcpy(s, "SING ");
	    break;
	case OVERFLOW:
	    strcpy(s, "O.F. ");
	    break;
	case UNDERFLOW:
	    strcpy(s, "U.F. ");
	    break;
	case TLOSS:
	    strcpy(s, "TLOSS ");
	    break;
	default:
	    strcpy(s, "Undef. ");
	    break;
    }
    strcat(s, "err, func. ");
    strcat(s, except -> name);

    MathError = s;

    PerformMEAction();

    return TRUE;
}

[ RETURN TO DIRECTORY ]