Mercurial > fife-parpg
comparison ext/libpng-1.2.29/contrib/visupng/cexcept.h @ 0:4a0efb7baf70
* Datasets becomes the new trunk and retires after that :-)
author | mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Sun, 29 Jun 2008 18:44:17 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4a0efb7baf70 |
---|---|
1 /*=== | |
2 cexcept.h 2.0.0 (2001-Jul-12-Thu) | |
3 Adam M. Costello <amc@cs.berkeley.edu> | |
4 | |
5 An interface for exception-handling in ANSI C (C89 and subsequent ISO | |
6 standards), developed jointly with Cosmin Truta <cosmin@cs.toronto.edu>. | |
7 | |
8 Copyright (c) 2001 Adam M. Costello and Cosmin Truta. Everyone | |
9 is hereby granted permission to do whatever they like with this | |
10 file, provided that if they modify it they take reasonable steps to | |
11 avoid confusing or misleading people about the authors, version, | |
12 and terms of use of the derived file. The copyright holders make | |
13 no guarantees regarding this file, and are not responsible for any | |
14 damage resulting from its use. | |
15 | |
16 Only user-defined exceptions are supported, not "real" exceptions like | |
17 division by zero or memory segmentation violations. | |
18 | |
19 If this interface is used by multiple .c files, they shouldn't include | |
20 this header file directly. Instead, create a wrapper header file that | |
21 includes this header file and then invokes the define_exception_type | |
22 macro (see below), and let your .c files include that header file. | |
23 | |
24 The interface consists of one type, one well-known name, and six macros. | |
25 | |
26 | |
27 define_exception_type(type_name); | |
28 | |
29 This macro is used like an external declaration. It specifies | |
30 the type of object that gets copied from the exception thrower to | |
31 the exception catcher. The type_name can be any type that can be | |
32 assigned to, that is, a non-constant arithmetic type, struct, union, | |
33 or pointer. Examples: | |
34 | |
35 define_exception_type(int); | |
36 | |
37 enum exception { out_of_memory, bad_arguments, disk_full }; | |
38 define_exception_type(enum exception); | |
39 | |
40 struct exception { int code; const char *msg; }; | |
41 define_exception_type(struct exception); | |
42 | |
43 Because throwing an exception causes the object to be copied (not | |
44 just once, but twice), programmers may wish to consider size when | |
45 choosing the exception type. | |
46 | |
47 | |
48 struct exception_context; | |
49 | |
50 This type may be used after the define_exception_type() macro has | |
51 been invoked. A struct exception_context must be known to both | |
52 the thrower and the catcher. It is expected that there be one | |
53 context for each thread that uses exceptions. It would certainly | |
54 be dangerous for multiple threads to access the same context. | |
55 One thread can use multiple contexts, but that is likely to be | |
56 confusing and not typically useful. The application can allocate | |
57 this structure in any way it pleases--automatic, static, or dynamic. | |
58 The application programmer should pretend not to know the structure | |
59 members, which are subject to change. | |
60 | |
61 | |
62 struct exception_context *the_exception_context; | |
63 | |
64 The Try/Catch and Throw statements (described below) implicitly | |
65 refer to a context, using the name the_exception_context. It is | |
66 the application's responsibility to make sure that this name yields | |
67 the address of a mutable (non-constant) struct exception_context | |
68 wherever those statements are used. Subject to that constraint, the | |
69 application may declare a variable of this name anywhere it likes | |
70 (inside a function, in a parameter list, or externally), and may | |
71 use whatever storage class specifiers (static, extern, etc) or type | |
72 qualifiers (const, volatile, etc) it likes. Examples: | |
73 | |
74 static struct exception_context | |
75 * const the_exception_context = &foo; | |
76 | |
77 { struct exception_context *the_exception_context = bar; ... } | |
78 | |
79 int blah(struct exception_context *the_exception_context, ...); | |
80 | |
81 extern struct exception_context the_exception_context[1]; | |
82 | |
83 The last example illustrates a trick that avoids creating a pointer | |
84 object separate from the structure object. | |
85 | |
86 The name could even be a macro, for example: | |
87 | |
88 struct exception_context ec_array[numthreads]; | |
89 #define the_exception_context (ec_array + thread_id) | |
90 | |
91 Be aware that the_exception_context is used several times by the | |
92 Try/Catch/Throw macros, so it shouldn't be expensive or have side | |
93 effects. The expansion must be a drop-in replacement for an | |
94 identifier, so it's safest to put parentheses around it. | |
95 | |
96 | |
97 void init_exception_context(struct exception_context *ec); | |
98 | |
99 For context structures allocated statically (by an external | |
100 definition or using the "static" keyword), the implicit | |
101 initialization to all zeros is sufficient, but contexts allocated | |
102 by other means must be initialized using this macro before they | |
103 are used by a Try/Catch statement. It does no harm to initialize | |
104 a context more than once (by using this macro on a statically | |
105 allocated context, or using this macro twice on the same context), | |
106 but a context must not be re-initialized after it has been used by a | |
107 Try/Catch statement. | |
108 | |
109 | |
110 Try statement | |
111 Catch (expression) statement | |
112 | |
113 The Try/Catch/Throw macros are capitalized in order to avoid | |
114 confusion with the C++ keywords, which have subtly different | |
115 semantics. | |
116 | |
117 A Try/Catch statement has a syntax similar to an if/else statement, | |
118 except that the parenthesized expression goes after the second | |
119 keyword rather than the first. As with if/else, there are two | |
120 clauses, each of which may be a simple statement ending with a | |
121 semicolon or a brace-enclosed compound statement. But whereas | |
122 the else clause is optional, the Catch clause is required. The | |
123 expression must be a modifiable lvalue (something capable of being | |
124 assigned to) of the same type (disregarding type qualifiers) that | |
125 was passed to define_exception_type(). | |
126 | |
127 If a Throw that uses the same exception context as the Try/Catch is | |
128 executed within the Try clause (typically within a function called | |
129 by the Try clause), and the exception is not caught by a nested | |
130 Try/Catch statement, then a copy of the exception will be assigned | |
131 to the expression, and control will jump to the Catch clause. If no | |
132 such Throw is executed, then the assignment is not performed, and | |
133 the Catch clause is not executed. | |
134 | |
135 The expression is not evaluated unless and until the exception is | |
136 caught, which is significant if it has side effects, for example: | |
137 | |
138 Try foo(); | |
139 Catch (p[++i].e) { ... } | |
140 | |
141 IMPORTANT: Jumping into or out of a Try clause (for example via | |
142 return, break, continue, goto, longjmp) is forbidden--the compiler | |
143 will not complain, but bad things will happen at run-time. Jumping | |
144 into or out of a Catch clause is okay, and so is jumping around | |
145 inside a Try clause. In many cases where one is tempted to return | |
146 from a Try clause, it will suffice to use Throw, and then return | |
147 from the Catch clause. Another option is to set a flag variable and | |
148 use goto to jump to the end of the Try clause, then check the flag | |
149 after the Try/Catch statement. | |
150 | |
151 IMPORTANT: The values of any non-volatile automatic variables | |
152 changed within the Try clause are undefined after an exception is | |
153 caught. Therefore, variables modified inside the Try block whose | |
154 values are needed later outside the Try block must either use static | |
155 storage or be declared with the "volatile" type qualifier. | |
156 | |
157 | |
158 Throw expression; | |
159 | |
160 A Throw statement is very much like a return statement, except that | |
161 the expression is required. Whereas return jumps back to the place | |
162 where the current function was called, Throw jumps back to the Catch | |
163 clause of the innermost enclosing Try clause. The expression must | |
164 be compatible with the type passed to define_exception_type(). The | |
165 exception must be caught, otherwise the program may crash. | |
166 | |
167 Slight limitation: If the expression is a comma-expression it must | |
168 be enclosed in parentheses. | |
169 | |
170 | |
171 Try statement | |
172 Catch_anonymous statement | |
173 | |
174 When the value of the exception is not needed, a Try/Catch statement | |
175 can use Catch_anonymous instead of Catch (expression). | |
176 | |
177 | |
178 Everything below this point is for the benefit of the compiler. The | |
179 application programmer should pretend not to know any of it, because it | |
180 is subject to change. | |
181 | |
182 ===*/ | |
183 | |
184 | |
185 #ifndef CEXCEPT_H | |
186 #define CEXCEPT_H | |
187 | |
188 | |
189 #include <setjmp.h> | |
190 | |
191 #define define_exception_type(etype) \ | |
192 struct exception_context { \ | |
193 jmp_buf *penv; \ | |
194 int caught; \ | |
195 volatile struct { etype etmp; } v; \ | |
196 } | |
197 | |
198 /* etmp must be volatile because the application might use automatic */ | |
199 /* storage for the_exception_context, and etmp is modified between */ | |
200 /* the calls to setjmp() and longjmp(). A wrapper struct is used to */ | |
201 /* avoid warnings about a duplicate volatile qualifier in case etype */ | |
202 /* already includes it. */ | |
203 | |
204 #define init_exception_context(ec) ((void)((ec)->penv = 0)) | |
205 | |
206 #define Try \ | |
207 { \ | |
208 jmp_buf *exception__prev, exception__env; \ | |
209 exception__prev = the_exception_context->penv; \ | |
210 the_exception_context->penv = &exception__env; \ | |
211 if (setjmp(exception__env) == 0) { \ | |
212 if (&exception__prev) | |
213 | |
214 #define exception__catch(action) \ | |
215 else { } \ | |
216 the_exception_context->caught = 0; \ | |
217 } \ | |
218 else { \ | |
219 the_exception_context->caught = 1; \ | |
220 } \ | |
221 the_exception_context->penv = exception__prev; \ | |
222 } \ | |
223 if (!the_exception_context->caught || action) { } \ | |
224 else | |
225 | |
226 #define Catch(e) exception__catch(((e) = the_exception_context->v.etmp, 0)) | |
227 #define Catch_anonymous exception__catch(0) | |
228 | |
229 /* Try ends with if(), and Catch begins and ends with else. This */ | |
230 /* ensures that the Try/Catch syntax is really the same as the */ | |
231 /* if/else syntax. */ | |
232 /* */ | |
233 /* We use &exception__prev instead of 1 to appease compilers that */ | |
234 /* warn about constant expressions inside if(). Most compilers */ | |
235 /* should still recognize that &exception__prev is never zero and */ | |
236 /* avoid generating test code. */ | |
237 | |
238 #define Throw \ | |
239 for (;; longjmp(*the_exception_context->penv, 1)) \ | |
240 the_exception_context->v.etmp = | |
241 | |
242 | |
243 #endif /* CEXCEPT_H */ |