#ifndef lib_try_h #define lib_try_h /* Cesar project {{{ * * Copyright (C) 2007 Spidcom * * <<>> * * }}} */ /** * \file lib/try.h * \brief Light exception system. * \ingroup lib * * This system mimics C++ exception handling using C setjmp/longjmp. Hey, but * this is not as safe as C++ exceptions! * * Here is an example use: * * \code * try_begin * { * ...some code... * try_throw (code thrown); * ...some code... * } * try_catch (code to catch) * { * ...handle exception... * } * try_always * { * ...optional code always executed when leaving this block scope... * } * try_end; * \endcode * * Main usage should be test code and fatal error trapping. This is not safe * and fast enough to be used for production code. * * When an exception is thrown, it is caught by each try block in order to * clean up after itself. */ #include /** Pointer to the most recently set setjmp context. */ extern jmp_buf *try_state_; /** Reserved catch codes. */ enum try_code_t { /** This is reserved. */ TRY_CODE_NONE, /** Thrown for fatal error. */ TRY_CODE_FATAL, /** Thrown for test failure. */ TRY_CODE_TEST_FAILURE, }; /** Begin a try block. */ #define try_begin try_begin_ /** Define the catch block inside a try block. */ #define try_catch(code) try_catch_(code) /** Define the always block inside a try block. */ #define try_always try_always_ /** End a try block. */ #define try_end try_end_ #define try_begin_ \ { \ int thrown_; \ bool caught_; \ jmp_buf *old_try_state_ = try_state_; \ jmp_buf this_try_state_; \ try_state_ = &this_try_state_; \ /* ANSI says assigning setjmp return value is forbidden, */ \ /* this code is not portable... */ \ thrown_ = setjmp (*try_state_); \ caught_ = false; \ if (thrown_ == 0) \ { #define try_catch_(code) \ } \ else \ { \ caught_ = thrown_ == (code); \ if (caught_) \ { #define try_always_ \ } \ } \ { \ { #define try_end_ \ } \ } \ try_state_ = old_try_state_; \ if (thrown_ != 0 && !caught_) \ { \ /* Jump again. */ \ dbg_assert_print (try_state_, "uncaught exception"); \ longjmp (*try_state_, thrown_); \ } \ } /** Throw an exception code. */ #define try_throw(code) try_throw_(code) #define try_throw_(code) \ do { \ longjmp (*try_state_, (code)); \ } while (0) #endif /* lib_try_h */