+++ /dev/null
-/*===
-cexcept.h 1.0.0 (2000-Jun-21-Wed)
-Adam M. Costello <amc@cs.berkeley.edu>
-
-An interface for exception-handling in ANSI C, developed jointly with
-Cosmin Truta <cosmin@cs.toronto.edu>.
-
- Copyright (c) 2000 Adam M. Costello and Cosmin Truta. Everyone
- is hereby granted permission to do whatever they like with this
- file, provided that if they modify it they take reasonable steps to
- avoid confusing or misleading people about the authors, version,
- and terms of use of the derived file. The copyright holders make
- no guarantees about the correctness of this file, and are not
- responsible for any damage resulting from its use.
-
-If this interface is used by multiple .c files, they shouldn't include
-this header file directly. Instead, create a wrapper header file that
-includes this header file and then invokes the define_exception_type
-macro (see below), and let your .c files include that header file.
-
-The interface consists of one type, one well-known name, and six macros.
-
-
-define_exception_type(type_name);
-
- This macro is used like an external declaration. It specifies
- the type of object that gets copied from the exception thrower to
- the exception catcher. The type_name can be any type that can be
- assigned to, that is, a non-constant arithmetic type, struct, union,
- or pointer. Examples:
-
- define_exception_type(int);
-
- enum exception { out_of_memory, bad_arguments, disk_full };
- define_exception_type(enum exception);
-
- struct exception { int code; const char *msg; };
- define_exception_type(struct exception);
-
-
-struct exception_context;
-
- This type may be used after the define_exception_type() macro has
- been invoked. A struct exception_context must be known to both
- the thrower and the catcher. It is expected that there be one
- context for each thread that uses exceptions. It would certainly
- be dangerous for multiple threads to access the same context.
- One thread can use multiple contexts, but that is likely to be
- confusing and not typically useful. The application can allocate
- this structure in any way it pleases--automatic, static, or dynamic.
- The application programmer should pretend not to know the structure
- members, which are subject to change.
-
-
-struct exception_context *the_exception_context;
-
- The Try/Catch and Throw statements (described below) implicitly
- refer to a context, using the name the_exception_context. It is
- the application's responsibility to make sure that this name yields
- the address of a mutable (non-constant) struct exception_context
- wherever those statements are used. Subject to that constraint, the
- application may declare a variable of this name anywhere it likes
- (inside a function, in a parameter list, or externally), and may
- use whatever storage class specifiers (static, extern, etc) or type
- qualifiers (const, volatile) it likes. Examples:
-
- static struct exception_context
- * const the_exception_context = &foo;
-
- { struct exception_context *the_exception_context = bar; ... }
-
- int blah(struct exception_context *the_exception_context, ...);
-
- extern struct exception_context the_exception_context[1];
-
- The last example illustrates a trick that avoids creating a pointer
- object separate from the structure object.
-
- The name could even be a macro, for example:
-
- struct exception_context ec_array[numthreads];
- #define the_exception_context (ec_array + thread_id)
-
- Be aware that the_exception_context is used several times by the
- Try/Catch/Throw macros, so it shouldn't be expensive or have side
- effects. The expansion must be a drop-in replacement for an
- identifier, so it's safest to put parentheses around it.
-
-
-void init_exception_context(struct exception_context *ec);
-
- For context structures allocated statically (by an external
- definition or using the "static" keyword), the implicit
- initialization to all zeros is sufficient, but contexts allocated
- by other means must be initialized using this macro before they
- are used by a Try/Catch statement. It does no harm to initialize
- a context more than once (by using this macro on a statically
- allocated context, or using this macro twice on the same context),
- but a context must not be re-initialized after it has been used by a
- Try/Catch statement.
-
-
-Try statement
-Catch (expression) statement
-
- The Try/Catch/Throw macros are capitalized in order to avoid
- confusion with the C++ keywords, which have subtly different
- semantics.
-
- A Try/Catch statement has a syntax similar to an if/else
- statement, except that the parenthesized expression goes after
- the second keyword rather than the first. As with if/else,
- there are two clauses, each of which may be a simple statement
- ending with a semicolon or a brace-enclosed compound statement.
- But whereas the else clause is optional, the Catch clause is
- required. The expression must be a modifiable lvalue (something
- capable of being assigned to) of the exact same type passed to
- define_exception_type().
-
- If a Throw that uses the same exception context as the Try/Catch is
- executed within the Try clause (typically within a function called
- by the Try clause), and the exception is not caught by a nested
- Try/Catch statement, then a copy of the exception will be assigned
- to the expression, and control will jump to the Catch clause. If no
- such Throw is executed, then the assignment is not performed, and
- the Catch clause is not executed.
-
- Regardless of whether an exception is caught, the expression is
- always evaluated exactly once, which is significant if it has side
- effects, for example:
-
- Try foo();
- Catch (p[++i].e) { ... }
-
- IMPORTANT: Jumping into or out of a Try clause (for example via
- return, break, continue, goto, longjmp) is forbidden--the compiler
- will not complain, but bad things will happen at run-time. Jumping
- into or out of a Catch clause is okay, and so is jumping around
- inside a Try clause. In many cases where one is tempted to return
- from a Try clause, it will suffice to use Throw, and then return
- from the Catch clause. Another option is to set a flag variable and
- use goto to jump to the end of the Try clause, then check the flag
- after the Try/Catch statement.
-
- IMPORTANT: The values of any non-volatile automatic variables
- changed within the Try clause are undefined after an exception is
- caught. Therefore, variables modified inside the Try block whose
- values are needed later outside the Try block must either use static
- storage or be declared with the "volatile" type qualifier.
-
-
-Throw expression;
-
- A Throw statement is very much like a return statement, except that
- the expression is required. Whereas return jumps back to the place
- where the current function was called, Throw jumps back to the Catch
- clause of the innermost enclosing Try clause. The expression must
- be compatible with the type passed to define_exception_type(). The
- exception must be caught, otherwise the program may crash.
-
- Slight limitation: If the expression is a comma-expression it must
- be enclosed in parentheses.
-
-
-Try statement
-Catch_anonymous statement
-
- When the value of the exception is not needed, a Try/Catch statement
- can use Catch_anonymous instead of Catch (expression).
-
-
-Everything below this point is for the benefit of the compiler. The
-application programmer should pretend not to know any of it, because it
-is subject to change.
-
-===*/
-
-
-#ifndef CEXCEPT_H
-#define CEXCEPT_H
-
-
-#include <setjmp.h>
-
-#define define_exception_type(etype) \
-struct exception__state { \
- etype *exception; \
- jmp_buf env; \
-}
-
-struct exception_context { \
- struct exception__state *last; \
- int caught; \
-};
-
-#define init_exception_context(ec) ((void)((ec)->last = 0))
-
-#define Catch(e) exception__catch(&(e))
-#define Catch_anonymous exception__catch(0)
-
-#define Try \
- { \
- struct exception__state *exception__p, exception__s; \
- int exception__i; \
- exception__p = the_exception_context->last; \
- the_exception_context->last = &exception__s; \
- for (exception__i = 0; ; exception__i = 1) \
- if (exception__i) { \
- if (setjmp(exception__s.env) == 0) { \
- if (&exception__s)
-
-#define exception__catch(e_addr) \
- else { } \
- the_exception_context->caught = 0; \
- } \
- else the_exception_context->caught = 1; \
- the_exception_context->last = exception__p; \
- break; \
- } \
- else exception__s.exception = e_addr; \
- } \
- if (!the_exception_context->caught) { } \
- else
-
-/* Try ends with if(), and Catch begins and ends with else. This */
-/* ensures that the Try/Catch syntax is really the same as the */
-/* if/else syntax. */
-/* */
-/* We use &exception__s instead of 1 to appease compilers that */
-/* warn about constant expressions inside if(). Most compilers */
-/* should still recognize that &exception__s is never zero and avoid */
-/* generating test code. */
-/* */
-/* We use the variable exception__i to start the loop at the bottom, */
-/* rather than jump into the loop using a switch statement, to */
-/* appease compilers that warn about jumping into loops. */
-
-#define Throw \
- for (;; longjmp(the_exception_context->last->env, 1)) \
- if (the_exception_context->last->exception) \
- *the_exception_context->last->exception =
-
-
-#endif /* CEXCEPT_H */