Add a new EXCEPT_CODE macro to get the exception code for the current
[obnox/wireshark/wip.git] / epan / exceptions.h
1 #ifndef __EXCEPTIONS_H__
2 #define __EXCEPTIONS_H__
3
4 #ifndef XCEPT_H
5 #include "except.h"
6 #endif
7
8 /* Ethereal has only one exception group, to make these macros simple */
9 #define XCEPT_GROUP_ETHEREAL 1
10
11 /* Ethereal's exceptions */
12 #define BoundsError             1       /* Index is out of range */
13 #define ReportedBoundsError     2       /* Index is beyond reported length (not cap_len) */
14 #define TypeError               3       /* During dfilter parsing */
15
16 /* Usage:
17  *
18  * TRY {
19  *      code;
20  * }
21  *
22  * CATCH(exception) {
23  *      code;
24  * }
25  *
26  * CATCH2(exception1, exception2) {
27  *      code;
28  * }
29  *
30  * CATCH_ALL {
31  *      code;
32  * }
33  *
34  * FINALLY {
35  *      code;
36  * }
37  *
38  * ENDTRY;
39  *
40  * ********* Never use 'goto' or 'return' inside the TRY, CATCH, CATCH_ALL,
41  * ********* or FINALLY blocks. Execution must proceed through ENDTRY before
42  * ********* branching out.
43  *
44  * This is really something like:
45  *
46  * {
47  *      x = setjmp()
48  *      if (x == 0) {
49  *              <TRY code>
50  *      }
51  *      else if (x == 1) {
52  *              <CATCH(1) code>
53  *      }
54  *      else if (x == 2) {
55  *              <CATCH(2) code>
56  *      }
57  *      else if (x == 3 || x == 4) {
58  *              <CATCH2(3,4) code>
59  *      }
60  *      else {
61  *              <CATCH_ALL code> {
62  *      }
63  *      <FINALLY code>
64  * }<ENDTRY tag>
65  *
66  * All CATCH's must precede a CATCH_ALL.
67  * FINALLY must occur after any CATCH or CATCH_ALL.
68  * ENDTRY marks the end of the TRY code.
69  * TRY and ENDTRY are the mandatory parts of a TRY block.
70  * CATCH, CATCH_ALL, and FINALLY are all optional (although
71  * you'll probably use at least one, otherwise why "TRY"?)
72  *
73  * GET_MESSAGE  returns string ptr to exception message
74  *              when exception is thrown via THROW_MESSAGE()
75  *
76  * To throw/raise an exception.
77  *
78  * THROW(exception)
79  * RETHROW                              rethrow the caught exception
80  *
81  * A cleanup callback is a function called in case an exception occurs
82  * and is not caught. It should be used to free any dynamically-allocated data.
83  * A pop or call_and_pop should occur at the same statement-nesting level
84  * as the push.
85  *
86  * CLEANUP_CB_PUSH(func, data)
87  * CLEANUP_CB_POP
88  * CLEANUP_CB_CALL_AND_POP
89  */
90
91
92
93 #define TRY \
94 {\
95         except_t *exc; \
96         static const except_id_t catch_spec[] = { \
97                 { XCEPT_GROUP_ETHEREAL, XCEPT_CODE_ANY } }; \
98         except_try_push(catch_spec, 1, &exc); \
99         if (exc == 0) { \
100                 /* user's code goes here */
101
102 #define ENDTRY \
103         } \
104         except_try_pop();\
105 }
106
107 #define CATCH(x) \
108         } \
109         else if (exc->except_id.except_code == (x)) { \
110                 /* user's code goes here */
111
112 #define CATCH2(x,y) \
113         } \
114         else if (exc->except_id.except_code == (x) || exc->except_id.except_code == (y)) { \
115                 /* user's code goes here */
116
117 #define CATCH_ALL \
118         } \
119         else { \
120                 /* user's code goes here */
121
122 #define FINALLY \
123         } \
124         { \
125                 /* user's code goes here */
126
127 #define THROW(x) \
128         except_throw(XCEPT_GROUP_ETHEREAL, (x), "XCEPT_GROUP_ETHEREAL")
129
130 #define THROW_MESSAGE(x, y) \
131         except_throw(XCEPT_GROUP_ETHEREAL, (x), (y))
132
133 #define GET_MESSAGE                     except_message(exc)
134
135 #define RETHROW                         except_rethrow(exc)
136
137 #define EXCEPT_CODE                     except_code(exc)
138
139 /* Register cleanup functions in case an exception is thrown and not caught.
140  * From the Kazlib documentation, with modifications for use with the
141  * Ethereal-specific macros:
142  *
143  * CLEANUP_PUSH(func, arg)
144  *
145  *  The call to CLEANUP_PUSH shall be matched with a call to
146  *  CLEANUP_CALL_AND_POP or CLEANUP_POP which must occur in the same
147  *  statement block at the same level of nesting. This requirement allows
148  *  an implementation to provide a CLEANUP_PUSH macro which opens up a
149  *  statement block and a CLEANUP_POP which closes the statement block.
150  *  The space for the registered pointers can then be efficiently
151  *  allocated from automatic storage.
152  *
153  *  The CLEANUP_PUSH macro registers a cleanup handler that will be
154  *  called if an exception subsequently occurs before the matching
155  *  CLEANUP_[CALL_AND_]POP is executed, and is not intercepted and
156  *  handled by a try-catch region that is nested between the two.
157  *
158  *  The first argument to CLEANUP_PUSH is a pointer to the cleanup
159  *  handler, a function that returns nothing and takes a single
160  *  argument of type void*. The second argument is a void* value that
161  *  is registered along with the handler.  This value is what is passed
162  *  to the registered handler, should it be called.
163  *
164  *  Cleanup handlers are called in the reverse order of their nesting:
165  *  inner handlers are called before outer handlers.
166  *
167  *  The program shall not leave the cleanup region between
168  *  the call to the macro CLEANUP_PUSH and the matching call to
169  *  CLEANUP_[CALL_AND_]POP by means other than throwing an exception,
170  *  or calling CLEANUP_[CALL_AND_]POP.
171  *
172  *  Within the call to the cleanup handler, it is possible that new
173  *  exceptions may happen.  Such exceptions must be handled before the
174  *  cleanup handler terminates. If the call to the cleanup handler is
175  *  terminated by an exception, the behavior is undefined. The exception
176  *  which triggered the cleanup is not yet caught; thus the program
177  *  would be effectively trying to replace an exception with one that
178  *  isn't in a well-defined state.
179  *
180  *
181  * CLEANUP_POP and CLEANUP_CALL_AND_POP
182  *
183  *  A call to the CLEANUP_POP or CLEANUP_CALL_AND_POP macro shall match
184  *  each call to CLEANUP_PUSH which shall be in the same statement block
185  *  at the same nesting level.  It shall match the most recent such a
186  *  call that is not matched by a previous CLEANUP_[CALL_AND_]POP at
187  *  the same level.
188  *
189  *  These macros causes the registered cleanup handler to be removed. If
190  *  CLEANUP_CALL_AND_POP is called, the cleanup handler is called.
191  *  In that case, the registered context pointer is passed to the cleanup
192  *  handler. If CLEANUP_POP is called, the cleanup handler is not called.
193  *
194  *  The program shall not leave the region between the call to the
195  *  macro CLEANUP_PUSH and the matching call to CLEANUP_[CALL_AND_]POP
196  *  other than by throwing an exception, or by executing the
197  *  CLEANUP_CALL_AND_POP.
198  *
199  */
200
201
202 #define CLEANUP_PUSH(f,a)               except_cleanup_push((f),(a))
203 #define CLEANUP_POP                     except_cleanup_pop(0)
204 #define CLEANUP_CALL_AND_POP            except_cleanup_pop(1)
205
206 #endif /* __EXCEPTIONS_H__ */