1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/templates/cexcept.h Fri Oct 28 22:58:50 2016 +0200
1.3 @@ -0,0 +1,251 @@
1.4 +/*===
1.5 +cexcept.h 2.0.1-Lichen (2016-Oct-27-Thu)
1.6 +A modified form of...
1.7 +cexcept.h 2.0.1 (2008-Jul-19-Sat)
1.8 +http://www.nicemice.net/cexcept/
1.9 +Adam M. Costello
1.10 +http://www.nicemice.net/amc/
1.11 +
1.12 +An interface for exception-handling in ANSI C (C89 and subsequent ISO
1.13 +standards), developed jointly with Cosmin Truta.
1.14 +
1.15 + Copyright (c) 2000-2008 Adam M. Costello and Cosmin Truta.
1.16 + Copyright (c) 2016 Paul Boddie (modified for Lichen).
1.17 + This software may be modified only if its author and version
1.18 + information is updated accurately, and may be redistributed
1.19 + only if accompanied by this unaltered notice. Subject to those
1.20 + restrictions, permission is granted to anyone to do anything
1.21 + with this software. The copyright holders make no guarantees
1.22 + regarding this software, and are not responsible for any damage
1.23 + resulting from its use.
1.24 +
1.25 +The cexcept interface is not compatible with and cannot interact
1.26 +with system exceptions (like division by zero or memory segmentation
1.27 +violation), compiler-generated exceptions (like C++ exceptions), or
1.28 +other exception-handling interfaces.
1.29 +
1.30 +When using this interface across multiple .c files, do not include
1.31 +this header file directly. Instead, create a wrapper header file that
1.32 +includes this header file and then invokes the define_exception_type
1.33 +macro (see below). The .c files should then include that header file.
1.34 +
1.35 +The interface consists of one type, one well-known name, and six macros.
1.36 +
1.37 +
1.38 +define_exception_type(type_name);
1.39 +
1.40 + This macro is used like an external declaration. It specifies
1.41 + the type of object that gets copied from the exception thrower to
1.42 + the exception catcher. The type_name can be any type that can be
1.43 + assigned to, that is, a non-constant arithmetic type, struct, union,
1.44 + or pointer. Examples:
1.45 +
1.46 + define_exception_type(int);
1.47 +
1.48 + enum exception { out_of_memory, bad_arguments, disk_full };
1.49 + define_exception_type(enum exception);
1.50 +
1.51 + struct exception { int code; const char *msg; };
1.52 + define_exception_type(struct exception);
1.53 +
1.54 + Because throwing an exception causes the object to be copied (not
1.55 + just once, but twice), programmers may wish to consider size when
1.56 + choosing the exception type.
1.57 +
1.58 +
1.59 +struct __exception_context;
1.60 +
1.61 + This type may be used after the define_exception_type() macro has
1.62 + been invoked. A struct __exception_context must be known to both
1.63 + the thrower and the catcher. It is expected that there be one
1.64 + context for each thread that uses exceptions. It would certainly
1.65 + be dangerous for multiple threads to access the same context.
1.66 + One thread can use multiple contexts, but that is likely to be
1.67 + confusing and not typically useful. The application can allocate
1.68 + this structure in any way it pleases--automatic, static, or dynamic.
1.69 + The application programmer should pretend not to know the structure
1.70 + members, which are subject to change.
1.71 +
1.72 +
1.73 +struct __exception_context *__the_exception_context;
1.74 +
1.75 + The __Try/__Catch and __Throw statements (described below) implicitly
1.76 + refer to a context, using the name __the_exception_context. It is
1.77 + the application's responsibility to make sure that this name yields
1.78 + the address of a mutable (non-constant) struct __exception_context
1.79 + wherever those statements are used. Subject to that constraint, the
1.80 + application may declare a variable of this name anywhere it likes
1.81 + (inside a function, in a parameter list, or externally), and may
1.82 + use whatever storage class specifiers (static, extern, etc) or type
1.83 + qualifiers (const, volatile, etc) it likes. Examples:
1.84 +
1.85 + static struct __exception_context
1.86 + * const __the_exception_context = &foo;
1.87 +
1.88 + { struct __exception_context *__the_exception_context = bar; ... }
1.89 +
1.90 + int blah(struct __exception_context *__the_exception_context, ...);
1.91 +
1.92 + extern struct __exception_context __the_exception_context[1];
1.93 +
1.94 + The last example illustrates a trick that avoids creating a pointer
1.95 + object separate from the structure object.
1.96 +
1.97 + The name could even be a macro, for example:
1.98 +
1.99 + struct __exception_context ec_array[numthreads];
1.100 + #define __the_exception_context (ec_array + thread_id)
1.101 +
1.102 + Be aware that __the_exception_context is used several times by the
1.103 + __Try/__Catch/__Throw macros, so it shouldn't be expensive or have side
1.104 + effects. The expansion must be a drop-in replacement for an
1.105 + identifier, so it's safest to put parentheses around it.
1.106 +
1.107 +
1.108 +void __init_exception_context(struct __exception_context *ec);
1.109 +
1.110 + For context structures allocated statically (by an external
1.111 + definition or using the "static" keyword), the implicit
1.112 + initialization to all zeros is sufficient, but contexts allocated
1.113 + by other means must be initialized using this macro before they
1.114 + are used by a __Try/__Catch statement. It does no harm to initialize
1.115 + a context more than once (by using this macro on a statically
1.116 + allocated context, or using this macro twice on the same context),
1.117 + but a context must not be re-initialized after it has been used by a
1.118 + __Try/__Catch statement.
1.119 +
1.120 +
1.121 +__Try statement
1.122 +__Catch (expression) statement
1.123 +
1.124 + The __Try/__Catch/__Throw macros are capitalized in order to avoid
1.125 + confusion with the C++ keywords, which have subtly different
1.126 + semantics.
1.127 +
1.128 + A __Try/__Catch statement has a syntax similar to an if/else statement,
1.129 + except that the parenthesized expression goes after the second
1.130 + keyword rather than the first. As with if/else, there are two
1.131 + clauses, each of which may be a simple statement ending with a
1.132 + semicolon or a brace-enclosed compound statement. But whereas
1.133 + the else clause is optional, the __Catch clause is required. The
1.134 + expression must be a modifiable lvalue (something capable of being
1.135 + assigned to) of the same type (disregarding type qualifiers) that
1.136 + was passed to define_exception_type().
1.137 +
1.138 + If a __Throw that uses the same exception context as the __Try/__Catch is
1.139 + executed within the __Try clause (typically within a function called
1.140 + by the __Try clause), and the exception is not caught by a nested
1.141 + __Try/__Catch statement, then a copy of the exception will be assigned
1.142 + to the expression, and control will jump to the __Catch clause. If no
1.143 + such __Throw is executed, then the assignment is not performed, and
1.144 + the __Catch clause is not executed.
1.145 +
1.146 + The expression is not evaluated unless and until the exception is
1.147 + caught, which is significant if it has side effects, for example:
1.148 +
1.149 + __Try foo();
1.150 + __Catch (p[++i].e) { ... }
1.151 +
1.152 + IMPORTANT: Jumping into or out of a __Try clause (for example via
1.153 + return, break, continue, goto, longjmp) is forbidden--the compiler
1.154 + will not complain, but bad things will happen at run-time. Jumping
1.155 + into or out of a __Catch clause is okay, and so is jumping around
1.156 + inside a __Try clause. In many cases where one is tempted to return
1.157 + from a __Try clause, it will suffice to use __Throw, and then return
1.158 + from the __Catch clause. Another option is to set a flag variable and
1.159 + use goto to jump to the end of the __Try clause, then check the flag
1.160 + after the __Try/__Catch statement.
1.161 +
1.162 + IMPORTANT: The values of any non-volatile automatic variables
1.163 + changed within the __Try clause are undefined after an exception is
1.164 + caught. Therefore, variables modified inside the __Try block whose
1.165 + values are needed later outside the __Try block must either use static
1.166 + storage or be declared with the "volatile" type qualifier.
1.167 +
1.168 +
1.169 +__Throw expression;
1.170 +
1.171 + A __Throw statement is very much like a return statement, except that
1.172 + the expression is required. Whereas return jumps back to the place
1.173 + where the current function was called, __Throw jumps back to the __Catch
1.174 + clause of the innermost enclosing __Try clause. The expression must
1.175 + be compatible with the type passed to define_exception_type(). The
1.176 + exception must be caught, otherwise the program may crash.
1.177 +
1.178 + Slight limitation: If the expression is a comma-expression, it must
1.179 + be enclosed in parentheses.
1.180 +
1.181 +
1.182 +__Try statement
1.183 +__Catch_anonymous statement
1.184 +
1.185 + When the value of the exception is not needed, a __Try/__Catch statement
1.186 + can use __Catch_anonymous instead of __Catch (expression).
1.187 +
1.188 +
1.189 +Everything below this point is for the benefit of the compiler. The
1.190 +application programmer should pretend not to know any of it, because it
1.191 +is subject to change.
1.192 +
1.193 +===*/
1.194 +
1.195 +
1.196 +#ifndef CEXCEPT_H
1.197 +#define CEXCEPT_H
1.198 +
1.199 +
1.200 +#include <setjmp.h>
1.201 +
1.202 +#define define_exception_type(etype) \
1.203 +struct __exception_context { \
1.204 + jmp_buf *penv; \
1.205 + int caught; \
1.206 + volatile struct { etype etmp; } v; \
1.207 +}
1.208 +
1.209 +/* etmp must be volatile because the application might use automatic */
1.210 +/* storage for __the_exception_context, and etmp is modified between */
1.211 +/* the calls to setjmp() and longjmp(). A wrapper struct is used to */
1.212 +/* avoid warnings about a duplicate volatile qualifier in case etype */
1.213 +/* already includes it. */
1.214 +
1.215 +#define __init_exception_context(ec) ((void)((ec)->penv = 0))
1.216 +
1.217 +#define __Try \
1.218 + { \
1.219 + jmp_buf *exception__prev, exception__env; \
1.220 + exception__prev = __the_exception_context->penv; \
1.221 + __the_exception_context->penv = &exception__env; \
1.222 + if (setjmp(exception__env) == 0) { \
1.223 + do
1.224 +
1.225 +#define exception__catch(action) \
1.226 + while (__the_exception_context->caught = 0, \
1.227 + __the_exception_context->caught); \
1.228 + } \
1.229 + else { \
1.230 + __the_exception_context->caught = 1; \
1.231 + } \
1.232 + __the_exception_context->penv = exception__prev; \
1.233 + } \
1.234 + if (!__the_exception_context->caught || action) { } \
1.235 + else
1.236 +
1.237 +#define __Catch(e) exception__catch(((e) = __the_exception_context->v.etmp, 0))
1.238 +#define __Catch_anonymous exception__catch(0)
1.239 +
1.240 +/* __Try ends with do, and __Catch begins with while(0) and ends with */
1.241 +/* else, to ensure that __Try/__Catch syntax is similar to if/else */
1.242 +/* syntax. */
1.243 +/* */
1.244 +/* The 0 in while(0) is expressed as x=0,x in order to appease */
1.245 +/* compilers that warn about constant expressions inside while(). */
1.246 +/* Most compilers should still recognize that the condition is always */
1.247 +/* false and avoid generating code for it. */
1.248 +
1.249 +#define __Throw \
1.250 + for (;; longjmp(*__the_exception_context->penv, 1)) \
1.251 + __the_exception_context->v.etmp =
1.252 +
1.253 +
1.254 +#endif /* CEXCEPT_H */