1 /*
2  ******************************
3  * Object Oriented Programming in C
4  *
5  * Author: Laurent Deniau, Laurent.Deniau@cern.ch
6  *
7  * License Public Domain Without Warranty
8  *
9  * For more information, please see the paper:
10  * http://cern.ch/Laurent.Deniau/html/oopc/exception.html
11  *
12  ******************************
13  */
14 
15 #ifndef EXCEPTION_H
16 #define EXCEPTION_H
17 
18 #ifndef __STDC__
19 #  error "exception.h needs ISO C compiler to work properly"
20 #endif
21 
22 #include <setjmp.h>
23 
24 /*
25   some useful macros
26 */
27 
28 #define _makeConcat_(a,b) a ## b
29 #define _concat_(a,b) _makeConcat_(a,b)
30 
31 #define _makeString_(a) # a
32 #define _string_(a) _makeString_(a)
33 
34 /*
35   choose context savings
36 */
37 
38 #ifdef sigsetjmp
39 #  define _save_context_buffer_(context)         sigsetjmp(context, 1)
40 #  define _restore_context_buffer_(context, val) siglongjmp(context, val)
41 #else
42 #  define _save_context_buffer_(context)         setjmp(context)
43 #  define _restore_context_buffer_(context, val) longjmp(context, val)
44 #endif
45 
46 /*
47   some hidden types used to handle exceptions
48 */
49 
50 /* type of stack of protected pointer */
51 struct _protectedPtr_ {
52   struct _protectedPtr_ *next;
53   void *ptr;
54   void (*func)(void*);
55 };
56 
57 /* type of stack of exception */
58 struct _exceptionContext_ {
59   struct _exceptionContext_ *next;
60   struct _protectedPtr_ *stack;
61   jmp_buf context;
62 };
63 
64 extern struct _exceptionContext_ *const _returnExceptionContext_;
65 extern struct _exceptionContext_ *_currentExceptionContext_;
66 
67 /* exception keywords */
68 #define try								 \
69   do {									 \
70     struct _exceptionContext_ *const _returnExceptionContext0_ =	 \
71                                               _returnExceptionContext_;	 \
72     struct _exceptionContext_ *const volatile _returnExceptionContext_ = \
73                  _returnExceptionContext0_ ? _returnExceptionContext0_:	 \
74                                              _currentExceptionContext_;	 \
75     struct _exceptionContext_ _localExceptionContext_ =			 \
76                                          { _currentExceptionContext_ };	 \
77     _currentExceptionContext_ = &_localExceptionContext_;		 \
78     (void)_returnExceptionContext_;					 \
79     do {								 \
80       int const exception =						 \
81               _save_context_buffer_(_currentExceptionContext_->context); \
82       if (!exception) {
83 
84 #define catch(except)							\
85       } else if ((int)(except) == exception) {				\
86         _currentExceptionContext_ = _currentExceptionContext_->next;
87 
88 #define catch_any							\
89       } else {								\
90         _currentExceptionContext_ = _currentExceptionContext_->next;
91 
92 #define endtry								\
93       }									\
94     } while(0);								\
95     if (_currentExceptionContext_ == &_localExceptionContext_) {	\
96       _currentExceptionContext_ = _currentExceptionContext_->next;	\
97     }									\
98   } while(0)
99 
100 #define rethrow throw(exception)
101 #define break_try break
102 #define return_try(...)						\
103   do {								\
104     _currentExceptionContext_ = _returnExceptionContext_;	\
105     return __VA_ARGS__;						\
106   } while(0)
107 
108 #ifdef DEBUG_THROW
109 #define throw(except)						\
110   _exceptionThrowDebug_(__FILE__, __LINE__, __func__,		\
111                         _string_(except), (int)(except))
112 #else
113 #define throw(except) _exceptionThrow_((int)(except))
114 #endif /* DEBUG_THROW */
115 
116 /*
117   pointer protection
118 */
119 
120 #define protectPtr(ptr, func)						    \
121   struct _protectedPtr_ _concat_(_protected_, ptr) =			    \
122   _protectPtr_(&_concat_(_protected_, ptr), (ptr), (void(*)(void *))(func))
123 
124 static inline struct _protectedPtr_
_protectPtr_(struct _protectedPtr_ * _ptr,void * ptr,void (* func)(void *))125 _protectPtr_(struct _protectedPtr_ *_ptr, void* ptr, void (*func)(void*))
126 {
127   if (_currentExceptionContext_) {
128     _ptr->next = _currentExceptionContext_->stack;
129     _ptr->ptr  = ptr;
130     _ptr->func = func;
131     _currentExceptionContext_->stack = _ptr;
132   }
133   return *_ptr;
134 }
135 
136 static inline void
unprotectPtr(void * ptr)137 unprotectPtr(void *ptr)
138 {
139   if (_currentExceptionContext_ &&
140       _currentExceptionContext_->stack &&
141       _currentExceptionContext_->stack->ptr == ptr)
142     _currentExceptionContext_->stack = _currentExceptionContext_->stack->next;
143 }
144 
145 /*
146   extern declarations
147 */
148 
149 extern void _exceptionThrow_(int except);
150 extern void _exceptionThrowDebug_(char const*, int, char const*, char const*,
151 				  int except);
152 #endif
153