Changes for Lee Busby's SIGFPE patch set.
Two new modules fpectl and fpetest.
Surround various and sundry f.p. operations with PyFPE_*_PROTECT macros.
diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
index ba95310..33d5392 100644
--- a/Modules/_tkinter.c
+++ b/Modules/_tkinter.c
@@ -724,10 +724,14 @@
 {
 	char *s;
 	double v;
+	int retval;
 
 	if (!PyArg_Parse(args, "s", &s))
 		return NULL;
-	if (Tcl_ExprDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR)
+	PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0)
+	retval = Tcl_ExprDouble (Tkapp_Interp (self), s, &v);
+	PyFPE_END_PROTECT
+	if (retval == TCL_ERROR)
 		return Tkinter_Error(self);
 	return Py_BuildValue("d", v);
 }
diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c
index 7e9de1f..438f010 100644
--- a/Modules/cmathmodule.c
+++ b/Modules/cmathmodule.c
@@ -247,7 +247,9 @@
 	if (!PyArg_ParseTuple(args, "D", &x))
 		return NULL;
 	errno = 0;
+	PyFPE_START_PROTECT("complex function", return 0)
 	x = (*func)(x);
+	PyFPE_END_PROTECT
 	CHECK(x.real);
 	CHECK(x.imag);
 	if (errno != 0)
diff --git a/Modules/fpectlmodule.c b/Modules/fpectlmodule.c
new file mode 100644
index 0000000..3fc5d06
--- /dev/null
+++ b/Modules/fpectlmodule.c
@@ -0,0 +1,244 @@
+/*
+     ---------------------------------------------------------------------  
+    /                       Copyright (c) 1996.                           \ 
+   |          The Regents of the University of California.                 |
+   |                        All rights reserved.                           |
+   |                                                                       |
+   |   Permission to use, copy, modify, and distribute this software for   |
+   |   any purpose without fee is hereby granted, provided that this en-   |
+   |   tire notice is included in all copies of any software which is or   |
+   |   includes  a  copy  or  modification  of  this software and in all   |
+   |   copies of the supporting documentation for such software.           |
+   |                                                                       |
+   |   This  work was produced at the University of California, Lawrence   |
+   |   Livermore National Laboratory under  contract  no.  W-7405-ENG-48   |
+   |   between  the  U.S.  Department  of  Energy and The Regents of the   |
+   |   University of California for the operation of UC LLNL.              |
+   |                                                                       |
+   |                              DISCLAIMER                               |
+   |                                                                       |
+   |   This  software was prepared as an account of work sponsored by an   |
+   |   agency of the United States Government. Neither the United States   |
+   |   Government  nor the University of California nor any of their em-   |
+   |   ployees, makes any warranty, express or implied, or  assumes  any   |
+   |   liability  or  responsibility  for the accuracy, completeness, or   |
+   |   usefulness of any information,  apparatus,  product,  or  process   |
+   |   disclosed,   or  represents  that  its  use  would  not  infringe   |
+   |   privately-owned rights. Reference herein to any specific  commer-   |
+   |   cial  products,  process,  or  service  by trade name, trademark,   |
+   |   manufacturer, or otherwise, does not  necessarily  constitute  or   |
+   |   imply  its endorsement, recommendation, or favoring by the United   |
+   |   States Government or the University of California. The views  and   |
+   |   opinions  of authors expressed herein do not necessarily state or   |
+   |   reflect those of the United States Government or  the  University   |
+   |   of  California,  and shall not be used for advertising or product   |
+    \  endorsement purposes.                                              / 
+     ---------------------------------------------------------------------  
+*/
+
+/*
+		  Floating point exception control module.
+
+   This Python module provides bare-bones control over floating point
+   units from several hardware manufacturers.  Specifically, it allows
+   the user to turn on the generation of SIGFPE whenever any of the
+   three serious IEEE 754 exceptions (Division by Zero, Overflow,
+   Invalid Operation) occurs.  We currently ignore Underflow and
+   Inexact Result exceptions, although those could certainly be added
+   if desired.
+
+   The module also establishes a signal handler for SIGFPE during
+   initialization.  This builds on code found in the Python
+   distribution at Include/pyfpe.h and Python/pyfpe.c.  If those files
+   are not in your Python distribution, find them in a patch at
+   ftp://icf.llnl.gov/pub/python/busby/patches.961108.tgz.
+
+   This module is only useful to you if it happens to include code
+   specific for your hardware and software environment.  If you can
+   contribute OS-specific code for new platforms, or corrections for
+   the code provided, it will be greatly appreciated.
+
+   ** Version 1.0: September 20, 1996.  Lee Busby, LLNL.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "Python.h"
+#include <signal.h>
+
+#ifndef WANT_SIGFPE_HANDLER
+/* Define locally if they are not defined in Python.  This gives only
+ * the limited control to induce a core dump in case of an exception.
+ */
+static jmp_buf PyFPE_jbuf;
+static int PyFPE_counter = 0;
+#endif
+
+typedef RETSIGTYPE Sigfunc(int);
+static Sigfunc sigfpe_handler;
+static void fpe_reset(Sigfunc *);
+
+static PyObject *fpe_error;
+void initfpectl(void);
+static PyObject *turnon_sigfpe            (PyObject *self,PyObject *args);
+static PyObject *turnoff_sigfpe           (PyObject *self,PyObject *args);
+
+static PyMethodDef fpectl_methods[] = {
+    {"turnon_sigfpe",		 (PyCFunction) turnon_sigfpe,		 1},
+    {"turnoff_sigfpe",		 (PyCFunction) turnoff_sigfpe, 	         1},
+    {0,0}
+};
+
+static PyObject *turnon_sigfpe(PyObject *self,PyObject *args)
+{
+    /* Do any architecture-specific one-time only initialization here. */
+
+    fpe_reset(sigfpe_handler);
+    Py_INCREF (Py_None);
+    return Py_None;
+}
+
+static void fpe_reset(Sigfunc *handler)
+{
+    /* Reset the exception handling machinery, and reset the signal
+     * handler for SIGFPE to the given handler.
+     */
+
+/*-- IRIX -----------------------------------------------------------------*/
+#if defined(sgi)
+    /* See man page on handle_sigfpes -- must link with -lfpe
+     * My usage doesn't follow the man page exactly.  Maybe somebody
+     * else can explain handle_sigfpes to me....
+     * cc -c -I/usr/local/python/include fpectlmodule.c
+     * ld -shared -o fpectlmodule.so fpectlmodule.o -lfpe 
+     */
+#include <sigfpe.h>
+    typedef void user_routine (unsigned[5], int[2]);
+    typedef void abort_routine (unsigned long);
+    handle_sigfpes(_OFF, 0,
+		 (user_routine *)0,
+		 _TURN_OFF_HANDLER_ON_ERROR,
+		 (abort_routine*)0);
+    handle_sigfpes(_ON, _EN_OVERFL | _EN_DIVZERO | _EN_INVALID,
+		 (user_routine *)0,
+		 _ABORT_ON_ERROR,
+		 (abort_routine*)0);
+    signal(SIGFPE, handler);
+
+/*-- SunOS and Solaris ----------------------------------------------------*/
+#elif defined(sun)
+    /* References: ieee_handler, ieee_sun, ieee_functions, and ieee_flags
+       man pages (SunOS or Solaris)
+       cc -c -I/usr/local/python/include fpectlmodule.c
+       ld -G -o fpectlmodule.so -L/opt/SUNWspro/lib fpectlmodule.o -lsunmath -lm
+     */
+#include <math.h>
+    char *mode="exception", *in="all", *out;
+    (void) nonstandard_arithmetic();
+    (void) ieee_flags("clearall",mode,in,&out);
+    (void) ieee_handler("set","common",(sigfpe_handler_type)handler);
+    signal(SIGFPE, handler);
+
+/*-- HPUX -----------------------------------------------------------------*/
+#elif defined(__hppa) || defined(hppa)
+    /* References:   fpsetmask man page */
+    /* cc -Aa +z -c -I/usr/local/python/include fpectlmodule.c */
+    /* ld -b -o fpectlmodule.sl fpectlmodule.o -lm */
+#include <math.h>
+    fpsetdefaults();
+    signal(SIGFPE, handler);
+
+/*-- IBM AIX --------------------------------------------------------------*/
+#elif defined(__AIX) || defined(_AIX)
+    /* References:   fp_trap, fp_enable man pages */
+#include <fptrap.h>
+    fp_trap(FP_TRAP_SYNC);
+    fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
+    signal(SIGFPE, handler);
+
+/*-- DEC ALPHA OSF --------------------------------------------------------*/
+#elif defined(__alpha)
+    /* References:   exception_intro, ieee man pages */
+    /* cc -c -I/usr/local/python/include fpectlmodule.c */
+    /* ld -shared -o fpectlmodule.so fpectlmodule.o */
+#include <machine/fpu.h>
+    unsigned long fp_control =
+    IEEE_TRAP_ENABLE_INV | IEEE_TRAP_ENABLE_DZE | IEEE_TRAP_ENABLE_OVF;
+    ieee_set_fp_control(fp_control);
+    signal(SIGFPE, handler);
+
+/*-- Cray Unicos ----------------------------------------------------------*/
+#elif defined(cray)
+    /* UNICOS delivers SIGFPE by default, but no matherr */
+#ifdef HAS_LIBMSET
+    libmset(-1);
+#endif
+    signal(SIGFPE, handler);
+
+/*-- Linux ----------------------------------------------------------------*/
+#elif defined(linux)
+    /* Linux delivers SIGFPE by default,
+       except for log(0), atanh(-1), 0.^0.
+     */
+    signal(SIGFPE, handler);
+
+/*-- NeXT -----------------------------------------------------------------*/
+#elif defined(NeXT) && defined(m68k) && defined(__GNUC__)
+    /* NeXT needs explicit csr set to generate SIGFPE */
+    asm("fmovel     #0x1400,fpcr");   /* set OVFL and ZD bits */
+    signal(SIGFPE, handler);
+
+/*-- Microsoft Windows, NT ------------------------------------------------*/
+#elif defined(_MSC_VER)
+    /* Reference: Visual C++ Books Online 4.2,
+       Run-Time Library Reference, _control87, _controlfp */
+#include <float.h>
+    unsigned int cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW;
+    (void)_controlfp(0, cw);
+    signal(SIGFPE, handler);
+
+/*-- Give Up --------------------------------------------------------------*/
+#else
+    fputs("Operation not implemented\n", stderr);
+#endif
+
+}
+
+static PyObject *turnoff_sigfpe(PyObject *self,PyObject *args)
+{
+    fputs("Operation not implemented\n", stderr);
+    Py_INCREF (Py_None);
+    return Py_None;
+}
+
+static void sigfpe_handler(int signo)
+{
+    fpe_reset(sigfpe_handler);
+    if(PyFPE_counter) {
+        longjmp(PyFPE_jbuf, 1);
+    } else {
+        Py_FatalError("Unprotected floating point exception");
+    }
+}
+
+void initfpectl(void)
+{
+    PyObject *m, *d;
+    static int already_initialized = 0;
+
+    if (already_initialized) return;
+    m = Py_InitModule("fpectl", fpectl_methods);
+    d = PyModule_GetDict(m);
+    fpe_error = PyString_FromString("fpectl.error");
+    PyDict_SetItemString(d, "error", fpe_error);
+
+    if (PyErr_Occurred())
+	Py_FatalError("Cannot initialize module fpectl");
+    already_initialized = 1;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/Modules/fpetestmodule.c b/Modules/fpetestmodule.c
new file mode 100644
index 0000000..2156afb
--- /dev/null
+++ b/Modules/fpetestmodule.c
@@ -0,0 +1,228 @@
+/*
+     ---------------------------------------------------------------------  
+    /                       Copyright (c) 1996.                           \ 
+   |          The Regents of the University of California.                 |
+   |                        All rights reserved.                           |
+   |                                                                       |
+   |   Permission to use, copy, modify, and distribute this software for   |
+   |   any purpose without fee is hereby granted, provided that this en-   |
+   |   tire notice is included in all copies of any software which is or   |
+   |   includes  a  copy  or  modification  of  this software and in all   |
+   |   copies of the supporting documentation for such software.           |
+   |                                                                       |
+   |   This  work was produced at the University of California, Lawrence   |
+   |   Livermore National Laboratory under  contract  no.  W-7405-ENG-48   |
+   |   between  the  U.S.  Department  of  Energy and The Regents of the   |
+   |   University of California for the operation of UC LLNL.              |
+   |                                                                       |
+   |                              DISCLAIMER                               |
+   |                                                                       |
+   |   This  software was prepared as an account of work sponsored by an   |
+   |   agency of the United States Government. Neither the United States   |
+   |   Government  nor the University of California nor any of their em-   |
+   |   ployees, makes any warranty, express or implied, or  assumes  any   |
+   |   liability  or  responsibility  for the accuracy, completeness, or   |
+   |   usefulness of any information,  apparatus,  product,  or  process   |
+   |   disclosed,   or  represents  that  its  use  would  not  infringe   |
+   |   privately-owned rights. Reference herein to any specific  commer-   |
+   |   cial  products,  process,  or  service  by trade name, trademark,   |
+   |   manufacturer, or otherwise, does not  necessarily  constitute  or   |
+   |   imply  its endorsement, recommendation, or favoring by the United   |
+   |   States Government or the University of California. The views  and   |
+   |   opinions  of authors expressed herein do not necessarily state or   |
+   |   reflect those of the United States Government or  the  University   |
+   |   of  California,  and shall not be used for advertising or product   |
+    \  endorsement purposes.                                              / 
+     ---------------------------------------------------------------------  
+*/
+
+/*
+		  Floating point exception test module.
+
+ */
+
+#include "Python.h"
+
+static PyObject *fpe_error;
+void initfpetest(void);
+static PyObject *test(PyObject *self,PyObject *args);
+static int db0(void);
+static int overflow(void);
+static int nest1(double);
+static int nest2(double);
+static double nest3(double);
+
+static PyMethodDef fpetest_methods[] = {
+    {"test",		 (PyCFunction) test,		 1},
+    {0,0}
+};
+
+static PyObject *test(PyObject *self,PyObject *args)
+{
+    int i = 0, r;
+
+    fprintf(stderr,"Test trapping overflow\n");
+    r = overflow();
+    if(r){
+      fprintf(stderr,"(Note: No exception was raised.)\n");
+      PyErr_Clear();
+    }else{
+      fprintf(stderr,"Trapped:: ");
+      PyErr_Print();
+      PyErr_Clear();
+    }
+    i += r;
+
+    fprintf(stderr,"Test trapping division by zero\n");
+    r = db0();
+    if(r){
+      fprintf(stderr,"(Note: No exception was raised.)\n");
+      PyErr_Clear();
+    }else{
+      fprintf(stderr,"Trapped:: ");
+      PyErr_Print();
+      PyErr_Clear();
+    }
+    i += r;
+
+    fprintf(stderr,"Test nested protection zones, outer zone\n");
+    r = nest1(0.0);
+    if(r){
+      fprintf(stderr,"(Note: No exception was raised.)\n");
+      PyErr_Clear();
+    }else{
+      fprintf(stderr,"Trapped:: ");
+      PyErr_Print();
+      PyErr_Clear();
+    }
+    i += r;
+
+    fprintf(stderr,"Test nested protection zones, inner zone\n");
+    fprintf(stderr,"(Note: Return will apparently come from outer zone.)\n");
+    r = nest1(1.0);
+    if(r){
+      fprintf(stderr,"(Note: No exception was raised.)\n");
+      PyErr_Clear();
+    }else{
+      fprintf(stderr,"Trapped:: ");
+      PyErr_Print();
+      PyErr_Clear();
+    }
+    i += r;
+
+    fprintf(stderr,"Test nested protection zones, trailing outer zone\n");
+    r = nest1(2.0);
+    if(r){
+      fprintf(stderr,"(Note: No exception was raised.)\n");
+      PyErr_Clear();
+    }else{
+      fprintf(stderr,"Trapped:: ");
+      PyErr_Print();
+      PyErr_Clear();
+    }
+    i += r;
+
+    fprintf(stderr,"Test nested function calls, prior error\n");
+    r = nest2(0.0);
+    if(r){
+      fprintf(stderr,"(Note: No exception was raised.)\n");
+      PyErr_Clear();
+    }else{
+      fprintf(stderr,"Trapped:: ");
+      PyErr_Print();
+      PyErr_Clear();
+    }
+    i += r;
+
+    fprintf(stderr,"Test nested function calls, interior error\n");
+    r = nest2(1.0);
+    if(r){
+      fprintf(stderr,"(Note: No exception was raised.)\n");
+      PyErr_Clear();
+    }else{
+      fprintf(stderr,"Trapped:: ");
+      PyErr_Print();
+      PyErr_Clear();
+    }
+    i += r;
+
+    fprintf(stderr,"Test nested function calls, trailing error\n");
+    r = nest2(2.0);
+    if(r){
+      fprintf(stderr,"(Note: No exception was raised.)\n");
+      PyErr_Clear();
+    }else{
+      fprintf(stderr,"Trapped:: ");
+      PyErr_Print();
+      PyErr_Clear();
+    }
+    i += r;
+
+    fprintf(stderr,"Number of tests failed: %d\n", i);
+    Py_INCREF (Py_None);
+    return Py_None;
+}
+
+static int nest1(double x)
+{
+  double a = 1.0;
+  PyFPE_START_PROTECT("Division by zero, outer zone", return 0)
+  a = 1./x;
+    PyFPE_START_PROTECT("Division by zero, inner zone", return 0)
+    a = 1./(1. - x);
+    PyFPE_END_PROTECT
+  a = 1./(2. - x);
+  PyFPE_END_PROTECT
+  return(1);
+}
+
+static int nest2(double x)
+{
+  double a = 1.0;
+  PyFPE_START_PROTECT("Division by zero, prior error", return 0)
+  a = 1./x;
+  a = nest3(x);
+  a = 1./(2. - x);
+  PyFPE_END_PROTECT
+  return(1);
+}
+
+static double nest3(double x)
+{
+  double result;
+  PyFPE_START_PROTECT("Division by zero, nest3 error", return 0)
+  result = 1./(1. - x);
+  PyFPE_END_PROTECT
+  return result;
+}
+
+static int db0(void)
+{
+  double a = 1.0;
+  PyFPE_START_PROTECT("Division by zero", return 0)
+  a = 1./(a - 1.);
+  PyFPE_END_PROTECT
+  return(1);
+}
+
+static int overflow(void)
+{
+  double a, b = 1.e200;
+  PyFPE_START_PROTECT("Overflow", return 0)
+  a = b*b;
+  PyFPE_END_PROTECT
+  return(1);
+}
+
+void initfpetest(void)
+{
+    PyObject *m, *d;
+
+    m = Py_InitModule("fpetest", fpetest_methods);
+    d = PyModule_GetDict(m);
+    fpe_error = PyString_FromString("fpetest.error");
+    PyDict_SetItemString(d, "error", fpe_error);
+
+    if (PyErr_Occurred())
+	Py_FatalError("Cannot initialize module fpetest");
+}
diff --git a/Modules/imgfile.c b/Modules/imgfile.c
index 33266b9..779169d 100644
--- a/Modules/imgfile.c
+++ b/Modules/imgfile.c
@@ -387,8 +387,10 @@
 		iclose(image);
 		return NULL;
 	}
+	PyFPE_START_PROTECT("readscaled", return 0)
 	xfac = (float)xsize/(float)xwtd;
 	yfac = (float)ysize/(float)ywtd;
+	PyFPE_END_PROTECT
 	cdatap = PyString_AsString(rv);
 	idatap = (long *)cdatap;
 
diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c
index abf1d5b..bb4f1e8 100644
--- a/Modules/mathmodule.c
+++ b/Modules/mathmodule.c
@@ -80,7 +80,9 @@
 	if (!  PyArg_Parse(args, "d", &x))
 		return NULL;
 	errno = 0;
+	PyFPE_START_PROTECT("in math_1", return 0)
 	x = (*func)(x);
+	PyFPE_END_PROTECT
 	CHECK(x);
 	if (errno != 0)
 		return math_error();
@@ -97,7 +99,9 @@
 	if (! PyArg_Parse(args, "(dd)", &x, &y))
 		return NULL;
 	errno = 0;
+	PyFPE_START_PROTECT("in math_2", return 0)
 	x = (*func)(x, y);
+	PyFPE_END_PROTECT
 	CHECK(x);
 	if (errno != 0)
 		return math_error();
@@ -173,7 +177,9 @@
         if (! PyArg_Parse(args, "(dd)", &x, &y))
 		return NULL;
 	errno = 0;
+	PyFPE_START_PROTECT("ldexp", return 0)
 	x = ldexp(x, (int)y);
+	PyFPE_END_PROTECT
 	CHECK(x);
 	if (errno != 0)
 		return math_error();
diff --git a/Modules/mpzmodule.c b/Modules/mpzmodule.c
index 1f356e1..bf83109 100644
--- a/Modules/mpzmodule.c
+++ b/Modules/mpzmodule.c
@@ -1488,6 +1488,8 @@
 	/* let those bits come, let those bits go,
 	   e.g. dismantle mpzscratch, build PyFloatObject */
 
+	/* Can this overflow?  Dunno, protect against that possibility. */
+	PyFPE_START_PROTECT("mpz_float", return 0)
 	x = 0.0;
 	mulstate = 1.0;
 	while (i--) {
@@ -1495,6 +1497,7 @@
 		mulstate *= multiplier;
 		mpz_div_2exp(&mpzscratch, &mpzscratch, BITS_PER_MP_LIMB);
 	}
+	PyFPE_END_PROTECT
 
 	assert(mpz_cmp_ui(&mpzscratch, (unsigned long int)0) == 0);
 	mpz_clear(&mpzscratch);
diff --git a/Modules/stropmodule.c b/Modules/stropmodule.c
index cb062ad..8ddf37d 100644
--- a/Modules/stropmodule.c
+++ b/Modules/stropmodule.c
@@ -661,7 +661,9 @@
 		return NULL;
 	}
 	errno = 0;
+	PyFPE_START_PROTECT("strop_atof", return 0)
 	x = strtod(s, &end);
+	PyFPE_END_PROTECT
 	while (*end && isspace(Py_CHARMASK(*end)))
 		end++;
 	if (*end != '\0') {