Aug 16, 2006

Exceptions

Since C++ includes exceptions improves applications' lifetime while running, "catching" known errors always helps, but what about the pretty older (but nicer) C?? The following simulates Java's try-catch-finally. It's based on the code written by Francisco A. Márquez, on his book.

File exception.h

#ifndef __EXCEPTION_H__
#define __EXCEPTION_H__
#include [signal .h] //Replace with "lower-than" "greather-than"
#include [setjmp .h]

typedef int exception_t;

extern exception_t
ARITHMETIC, /* SIGFPE */
HANGUP, /* SIGHUP */
ILLEGAL_INSTRUCTION, /* SIGILL */
SEGMENT_VIOLATION, /* SIGSEGV */
TERMINATION, /* SIGTERM */
UNKNOWN;

extern jmp_buf __jmpbuf;

/*
* try {
* insert-code-here
* } catch (Exception) {
* deal-with-the-exception
* } finally {
* do-something
* }
* */
#define try {exception_t current_exception;\
sigset_t oset;\
struct sigaction oact;\
void exception_lock_signal (sigset_t *oset, struct sigaction *oact);\
void exception_unlock_signal (sigset_t *oset, struct sigaction *oact);\
exception_lock_signal (&oset, &oact);\
if ((current_exception = (exception_t) setjmp (__jmpbuf)) == 0)
#define catch(exception) else if (current_exception == (int) &exception)
#define finally exception_unlock_signal (&oset, &oact);}
#define throw(exception) longjmp (__jmpbuf, (int) &exception);

#endif

File exception.c

#include [errno .h] //Replace with "lower-than" "greather-than"
#include [stdio .h]
#include "exception.h"

exception_t
ARITHMETIC,
HANGUP,
ILLEGAL_INSTRUCTION,
SEGMENT_VIOLATION,
TERMINATION,
UNKNOWN;

jmp_buf __jmpbuf;

void exception_error (int err, char *str)
{
printf ("EXCEPTION ERROR: (%i) %s\n", err, str);
}

void exception_manager (int signal)
{
switch (signal) {
case SIGFPE:
throw (ARITHMETIC);
break;
case SIGHUP:
throw (HANGUP);
break;
case SIGILL:
throw (ILLEGAL_INSTRUCTION);
break;
case SIGSEGV:
throw (SEGMENT_VIOLATION);
break;
case SIGTERM:
throw (TERMINATION);
break;
default:
throw (UNKNOWN);
}
}

void exception_lock_signal (sigset_t *oset, struct sigaction *oact)
{
int error = 0;
sigset_t set;
struct sigaction act;

sigemptyset (&set);
sigaddset (&set, SIGFPE);
sigaddset (&set, SIGHUP);
sigaddset (&set, SIGILL);
sigaddset (&set, SIGSEGV);
sigaddset (&set, SIGTERM);
if ((error = sigprocmask (SIG_UNBLOCK, &set, oset)) == -1)
exception_error (errno, "sigprocmask");
act.sa_handler = exception_manager;
sigfillset (&act.sa_mask);
act.sa_flags = SA_RESETHAND;
if ((error = sigaction (SIGFPE, &act, oact)) == -1)
exception_error (errno, "sigaction SIGFPE");
if ((error = sigaction (SIGHUP, &act, oact)) == -1)
exception_error (errno, "sigaction SIGHUP");
if ((error = sigaction (SIGILL, &act, oact)) == -1)
exception_error (errno, "sigaction SIGILL");
if ((error = sigaction (SIGSEGV, &act, oact)) == -1)
exception_error (errno, "sigaction SIGSEGV");
if ((error = sigaction (SIGTERM, &act, oact)) == -1)
exception_error (errno, "sigaction SIGTERM");
}

void exception_unlock_signal (sigset_t *oset, struct sigaction *oact)
{
int error = 0;

if ((error = sigprocmask (SIG_SETMASK, oset, NULL)) == -1)
exception_error (error, "sigprockmask SIG_SETMASK");
if ((error = sigaction (SIGFPE, oact, NULL)) == -1)
exception_error (error, "sigaction SIGFPE");
if ((error = sigaction (SIGHUP, oact, NULL)) == -1)
exception_error (error, "sigaction SIGHUP");
if ((error = sigaction (SIGILL, oact, NULL)) == -1)
exception_error (error, "sigaction SIGILL");
if ((error = sigaction (SIGSEGV, oact, NULL)) == -1)
exception_error (error, "sigaction SIGSEGV");
if ((error = sigaction (SIGTERM, oact, NULL)) == -1)
exception_error (error, "sigaction SIGTERM");

}

And yes... there is also the example code:

#include [stdio .h] //Replace with "lower-than" "greather-than"
#include "exception.h"

int main ()
{
exception_t Error_de_Lectura;
int x;
try {
printf ("Protected scope. BEGIN\n");
strcpy (NULL, "Nice!");
printf ("Protected scope. END\n");
} catch (Error_de_Lectura) {
printf ("Reading error\n");
} catch (ARITHMETIC) {
printf ("Arithmetic error\n");
throw (Error_de_Lectura);
} catch (ILLEGAL_INSTRUCTION) {
printf ("Instruccion ilegal");
} catch (SEGMENT_VIOLATION) {
printf ("Segmentation fault!.\n");
x = 0 /0;
} finally {
printf ("Finally reached\n");
}
return 0;
}

Awesome, isn't it?.