summaryrefslogtreecommitdiff
path: root/cesar/lib/try.h
diff options
context:
space:
mode:
Diffstat (limited to 'cesar/lib/try.h')
-rw-r--r--cesar/lib/try.h120
1 files changed, 120 insertions, 0 deletions
diff --git a/cesar/lib/try.h b/cesar/lib/try.h
new file mode 100644
index 0000000000..563ad7c4dd
--- /dev/null
+++ b/cesar/lib/try.h
@@ -0,0 +1,120 @@
+#ifndef lib_try_h
+#define lib_try_h
+/* Cesar project {{{
+ *
+ * Copyright (C) 2007 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \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 <setjmp.h>
+
+/** 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_ = false; \
+ 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_); \
+ 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 */