/*
  Example of SIGFPE handling using fenv.h and signal.h
  
  Compile with
     gcc -lm -o fputest fputest.c

  Run with e.g.
     fputest iffi

  Synopsis
     fputest [tests]

  Input
     tests: a string of letters 'i' and 'f' for integer and float. For
            each letter, attempt to trigger and trap a SIGFPE using
            integer or floating-point division (1/0 or 1./0.). If not
            set, tests defaults to "f".

  Description:
     If all goes well, a series of lines is output, for instance
     $ ./fputest iffi
     Triggering integer SIGFPE: 1/0=(SIGFPE trapped)0
     Triggering floating SIGFPE: 1./0.=(SIGFPE trapped)0.000000
     Triggering floating SIGFPE: 1./0.=(SIGFPE trapped)0.000000
     Triggering integer SIGFPE: 1/0=(SIGFPE trapped)0

     If SIGFPE trapping is broken, the program will die with corrupted
     output and a last line such asending with "Floating point exception":
     $ ./fputest iffi
     Triggering integer SIGFPE: 1/0=(SIGFPE trapped)0
     Triggering floating SIGFPE: 1./0.=Floating point exception

  License (rather obviously for a short example file):
      Public domain
 */

// feenableexcpet is a GNU extension over fenv.h
#define _GNU_SOURCE 1
#include <fenv.h>
#include <signal.h>
#include <setjmp.h>
#include <stdio.h>
#include <string.h>

static jmp_buf jmp_point;

void catcher(int sig)
{
  printf("(SIGFPE trapped)");
  fflush(stdout);
  longjmp(jmp_point,1);
}

void worker(char type)
{
  int intval=0;
  float floatval=0;

  struct sigaction sigact;
  sigemptyset( &sigact.sa_mask );
  sigact.sa_flags = 0;
    sigact.sa_flags = sigact.sa_flags | SA_NODEFER | SA_RESETHAND;
  sigact.sa_handler = catcher;
  sigaction( SIGFPE, &sigact, NULL );
  feenableexcept(FE_ALL_EXCEPT);
  if (setjmp(jmp_point)) {
    if (type=='i') printf("%d\n", intval);
    if (type=='f') printf("%f\n", floatval);
  } else {
    if (type=='i') {
      printf("Triggering integer SIGFPE: 1/0=");
      fflush(stdout);
      intval=1/0; }
    if (type=='f') {
      printf("Triggering floating SIGFPE: 1./0.=");
      fflush(stdout);
      floatval=1./0.;
    }
  }
}

int main(int argc, char *argv[])
{
  int i;
  if (argc==1) worker('f');
  else for (i=0; i<strlen(argv[1]); i++) worker(argv[1][i]);

  return 0;
}
