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