OSSP CVS Repository

ossp - Check-in [1765]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 1765
Date: 2002-Jan-31 21:22:03 (local)
2002-Jan-31 20:22:03 (UTC)
User:rse
Branch:
Comment: final polishing
Tickets:
Inspections:
Files:
ossp-pkg/ex/ex.pod      1.16 -> 1.17     196 inserted, 205 deleted

ossp-pkg/ex/ex.pod 1.16 -> 1.17

--- ex.pod       2002/01/30 13:39:41     1.16
+++ ex.pod       2002/01/31 20:22:03     1.17
@@ -53,23 +53,24 @@
 B<OSSP ex> is a small B<ISO-C++> style exception handling library for
 use in the B<ISO-C> language. It allows you to use the paradigm of
 throwing and catching exceptions in order to reduce the amount of error
-handling code without making your program less robust. This is achieved
-by directly transferring exceptional return codes (and the program
-control flow) from the location where the exception is raised (throw
-point) to the location where it is handled (catch point) -- usually
-from a deeply nested sub-routine to a parent routine. All intermediate
-routines no longer have to make sure that the exceptional return codes
-from sub-routines are correctly passed back to the parent.
+handling code without making your program less robust. 
+
+This is achieved by directly transferring exceptional return codes (and
+the program control flow) from the location where the exception is
+raised (throw point) to the location where it is handled (catch point)
+-- usually from a deeply nested sub-routine to a parent routine. All
+intermediate routines no longer have to make sure that the exceptional
+return codes from sub-routines are correctly passed back to the parent.
 
 =head2 EXCEPTIONS
 
-An exception is a triple E<lt>I<class>,I<object>,I<value>E<gt> where
-I<class> identifies the class of the exception thrower, I<object>
-identifies the particular class instance of the exception thrower, and
-I<value> is the exceptional return code value the thrower wants to send
-to the catcher. All three parts are of type "C<void *>" internally,
-but every value can be used which can be (automatically) casted to the
-B<ISO-C> type "C<void *>". Exceptions are created on-the-fly by the
+An B<OSSP ex> exception is a triple
+E<lt>I<class>,I<object>,I<value>E<gt> where I<class> identifies the
+class of the exception thrower, I<object> identifies the particular
+class instance of the exception thrower, and I<value> is the exceptional
+return code value the thrower wants to communicate. All three parts are
+of type "C<void *>" internally, but every value is useable which can
+be lossless casted this type. Exceptions are created on-the-fly by the
 B<ex_throw> command.
 
 =head2 APPLICATION PROGRAMMER INTERFACE (API)
@@ -81,8 +82,8 @@
 =item B<ex_t> I<variable>;
 
 This is the declaration of an exception variable. It is usually never
-initialized manually. Instead it is initialized by an B<ex_catch> block
-and just used read-only inside the block. Such a variable of type
+initialized manually. Instead it is initialized by an B<ex_catch> clause
+and just used read-only inside its block. Such a variable of type
 B<ex_t> consists of six attributes:
 
 =over 2
@@ -90,108 +91,111 @@
 =item C<void *>I<ex_class>
 
 This is the I<class> argument of the B<ex_throw> call which created
-the exception. This globally and uniquely identifies the class of
+the exception. This should globally and uniquely identify the class of
 I<ex_value>. Usually this is a pointer to a static object (variable,
-structure or function) which identifies the thrower.
+structure or function) which identifies the class of the thrower and
+allows the catcher to correctly handle I<ex_value>.
 
 =item C<void *>I<ex_object>
 
 This is the I<object> argument of the B<ex_throw> call which created
-the exception. This globally and uniquely identifies the class instance
-of I<ex_value> (in case multiple instances exists). Usually this a
-pointer to a dynamic object (structure) which identifiers the particular
-instance of the thrower.
+the exception. This should globally and uniquely identify the class
+instance of I<ex_value> (in case multiple instances exists at all).
+Usually this a pointer to a dynamic object (structure) which identifiers
+the particular instance of the thrower. It is usually just an additional
+information to I<ex_value>.
 
 =item C<void *>I<ex_value>
 
-This is the I<value> argument of the B<ex_throw> call which created the
-exception. This is the exceptional return code which uniquely identifies
-the type of exception. Usually this is the value which is C<return>ed
-if no exceptions would be thrown. In the simple case this is just a
-numerical return code. In the complex case this can be a pointer to an
-arbitrary complex data structure describing the exception.
+This is the I<value> argument of the B<ex_throw> call which created
+the exception. This is the exceptional return code value which has to
+uniquely identify the type of exception. Usually this is the value which
+is C<return>ed if no exceptions would be thrown. In the simple case
+this is just a numerical return code. In the complex case this can be a
+pointer to an arbitrary complex data structure describing the exception.
 
 =item C<char *>I<ex_file> 
 
-This is the file name of the source where the B<ex_throw> call
-was performed. It is provided as an additional information about
-the throw point and is intended mainly for tracing and debugging
-purposes.
+This is the file name of the B<ISO-C> source where the B<ex_throw> call
+was performed. It is provided as an additional information about the
+throw point and is intended mainly for tracing and debugging purposes.
 
 =item C<int> I<ex_line>
 
-This is the line number inside the source file name where the
-B<ex_throw> call was performed. It is provided as an additional
+This is the line number inside the B<ISO-C> source file name where
+the B<ex_throw> call was performed. It is provided as an additional
 information about the throw point and is intended mainly for tracing and
 debugging purposes.
 
 =item C<char *>I<ex_func>
 
-This is the function name (if determinable, else "C<#NA#>") inside
-the source file name where the B<ex_throw> call was performed. It is
-provided as an additional information about the throw point and is
+This is the function name (if determinable, else "C<#NA#>") inside the
+B<ISO-C> source file name where the B<ex_throw> call was performed. It
+is provided as an additional information about the throw point and is
 intended mainly for tracing and debugging purposes.
 
 =back
 
 =item B<ex_try> I<BLOCK1> [B<ex_cleanup> I<BLOCK2>] B<ex_catch> (I<variable>) I<BLOCK3>
 
-This is the main construct provided by B<OSSP ex>. It is modeled after
-the B<ISO-C++> C<try>-C<catch> clause which in turn is very similar to
-an B<ISO-C> C<if>-C<else> clause. It consists of an B<ex_try> block
-I<BLOCK1> which forms the dynamic scope of the exception handling (i.e.
-exceptions directly thrown there or thrown from its sub-routines are
-catched), an optional B<ex_cleanup> block I<BLOCK2> for performing
-cleanup operations and an B<ex_catch> block I<BLOCK3> where the caught
-exceptions are handled.
+This is the primary syntactical construct provided by B<OSSP ex>. It
+is modeled after the B<ISO-C++> C<try>-C<catch> clause which in turn
+is very similar to an B<ISO-C> C<if>-C<else> clause. It consists of an
+B<ex_try> block I<BLOCK1> which forms the dynamic scope for exception
+handling (i.e. exceptions directly thrown there or thrown from its
+sub-routines are caught), an optional B<ex_cleanup> block I<BLOCK2> for
+performing cleanup operations and an B<ex_catch> block I<BLOCK3> where
+the caught exceptions are handled.
 
 The control flow in case no exception is thrown is simply I<BLOCK1>,
-optionally followed by I<BLOCK2>. I<BLOCK3> is skipped. The control flow
-in case an exception is thrown is: I<BLOCK1> (up to the statement where
-the exception is thrown), optionally followed by I<BLOCK2>, followed by
-I<BLOCK3>.
+optionally followed by I<BLOCK2>; I<BLOCK3> is skipped. The control
+flow in case an exception is thrown is: I<BLOCK1> (up to the statement
+where the exception is thrown only), optionally followed by I<BLOCK2>,
+followed by I<BLOCK3>.
     
-The B<ex_try>, B<ex_cleanup> and B<ex_catch> cannot be used seperately,
-they work only in combination. And in contrast to B<ISO-C++> there
-is only one B<ex_catch> block and not multiple ones (all B<OSSP ex>
-exceptions are of the same B<ISO-C> type B<ex_t>). If an exception is
-caught, it is stored in I<variable> for inspection (or re-throwing)
-inside the B<ex_catch> block. Although declared outside, the I<variable>
-is only valid within the B<ex_catch> block. But it can be re-used in
-following B<ex_try>/B<ex_catch> constructs, of course.
-
-The B<ex_try> block is a regular B<ISO-C> language block of
-statement(s), but it is not allowed to jump into it via C<goto> or
-C<longjmp>(3) or out of it via C<return>, C<goto> or C<longjmp>(3)
-because there is some hidden setup and cleanup that needs to be done by
-B<OSSP ex> regardless of whether an exception is caught. Jumping into
-an B<ex_try> clause would avoid doing the setup, and jumping out of it
-would avoid doing the cleanup. In both cases the result is a broken
-exception facility. Nevertheless you are allowed to nest B<ex_try>
+The B<ex_try>, B<ex_cleanup> and B<ex_catch> cannot be used separately,
+they work only in combination because they form a language clause
+as a whole. In contrast to B<ISO-C++> there is only one B<ex_catch>
+block and not multiple ones (all B<OSSP ex> exceptions are of the same
+B<ISO-C> type B<ex_t>). If an exception is caught, it is stored in
+I<variable> for inspection inside the B<ex_catch> block. Although having
+to be declared outside, the I<variable> value is only valid within
+the B<ex_catch> block. But the variable can be re-used in subsequent
+B<ex_catch> clauses, of course.
+
+The B<ex_try> block is a regular B<ISO-C> language statement block, but
+it is not allowed to jump into it via C<goto> or C<longjmp>(3) or out
+of it via C<break>, C<return>, C<goto> or C<longjmp>(3) because there
+is some hidden setup and cleanup that needs to be done by B<OSSP ex>
+regardless of whether an exception is caught. Jumping into an B<ex_try>
+clause would avoid doing the setup, and jumping out of it would avoid
+doing the cleanup. In both cases the result is a broken exception
+handling facility. Nevertheless you are allowed to nest B<ex_try>
 clauses.
 
 The B<ex_cleanup> and B<ex_catch> blocks are regular B<ISO-C> language
-block of statement(s) without any restrictions. You are even allowed to
-throw (and in the B<ex_catch> block to re-throw) an exception.
+statement blocks without any restrictions. You are even allowed to throw
+(and in the B<ex_catch> block to re-throw) an exception.
 
 There is just one subtle portability detail you have to remember about
 B<ex_try> blocks: all accessible B<ISO-C> objects have the (expected)
-values as of the time B<ex_throw> was called, except that the values of
-objects of automatic storage invocation duration that do not have the
-C<volatile> storage class I<and> have been changed between the B<ex_try>
-invocation and B<ex_throw> are indeterminate. This is both because
-you usually do not know which commands in the B<ex_try> were already
-successful before the exception was thrown and because the underlying
-B<ISO-C> setjmp(3) facility applies those restrictions.
+values as of the time B<ex_throw> was called, except that the values
+of objects of automatic storage invocation duration that do not have
+the C<volatile> storage class I<and> have been changed between the
+B<ex_try> invocation and B<ex_throw> are indeterminate. This is because
+both you usually do not know which commands in the B<ex_try> were
+already successful before the exception was thrown (logically speaking)
+and because the underlying B<ISO-C> setjmp(3) facility applies those
+restrictions (technically speaking).
 
 =item B<ex_throw>(I<class>, I<object>, I<value>);
 
-This is second main construct. It builds an exception from the supplied
-arguments and throws it. If an B<ex_try>/B<ex_catch> clause exists in
-the dynamic scope of the B<ex_throw> call, this exception is copied into
-the I<variable> of B<ex_catch> and the program control flow is continued
-in the B<ex_catch> block. If no B<ex_try>/B<ex_catch> clause exists in
-the dynamic scope of the B<ex_throw> call, the program C<abort>(3)s. The
+This builds an exception from the supplied arguments and throws it.
+If an B<ex_try>/B<ex_catch> clause formed the dynamic scope of the
+B<ex_throw> call, this exception is copied into the I<variable> of its
+B<ex_catch> clause and the program control flow is continued in the
+B<ex_catch> block. If no B<ex_try>/B<ex_catch> clause exists in the
+dynamic scope of the B<ex_throw> call, the program C<abort>(3)s. The
 B<ex_throw> can be performed everywhere, including inside B<ex_try> and
 B<ex_catch> blocks.
 
@@ -200,26 +204,27 @@
 This is only valid within an B<ex_catch> block and re-throws
 the current exception (in I<variable>). It is similar to the
 call B<ex_throw>(I<variable>.ex_class, I<variable>.ex_object,
-I<variable>.ex_value) but with the difference that the C<ex_file>,
-C<ex_line> and C<ex_func> elements of the thrown exception are kept.
+I<variable>.ex_value) except for the difference that the C<ex_file>,
+C<ex_line> and C<ex_func> elements of the caught exception are passed
+through as it would have been never caught.
 
 =item B<ex_shield> I<BLOCK>
 
 This directive executes I<BLOCK> while shielding it against the throwing
 of exceptions, i.e., inside the dynamic scope of B<ex_shield> all
-B<ex_throw> operations are ignored.
+B<ex_throw> operations are silently ignored.
 
 =item B<ex_catching>
 
-This is a boolean flag which can be tested inside a block to test
-whether the current scope is exception catching (by B<ex_catch>
-somewhere in the dynamic scope) or not.
+This is a boolean flag which can be checked inside the dynamic scope
+of an B<ex_try> clause to test whether the current scope is exception
+catching. 
 
 =item B<ex_shielding>
 
-This is a boolean flag which can be tested inside a block to test
-whether the current scope is exception shielding (by B<ex_shield>
-somewhere in the dynamic scope) or not.
+This is a boolean flag which can be checked inside the dynamic scope of
+an B<ex_shield> clause to test whether the current scope is exception
+shielding.
 
 =back
 
@@ -239,23 +244,25 @@
 
 =item B<__ex_mctx_struct>
 
-This is the contents of the machine context structure. A pointer to such
-a machine context is passed to the following macros as I<mctx>. 
+This holds the contents of the machine context structure. A pointer to
+such a machine context is passed to the following macros as I<mctx>.
 
-=item B<__ex_mctx_save>(I<mctx>)
+=item B<__ex_mctx_save>(__ex_mctx_struct *I<mctx>)
 
 This is called by the prolog of B<ex_try> to save the current machine
 context in I<mctx>. This function has to return true (not C<0>) after
 saving. If the machine context is restored (by B<__ex_mctx_restore>) it
-has to return false (C<0>).
+has to return false (C<0>). In other words, this function has to return
+twice and indicate the particular situation with the provided return
+code.
 
-=item B<__ex_mctx_restored>(I<mctx>)
+=item B<__ex_mctx_restored>(__ex_mctx_struct *I<mctx>)
 
 This is called by the epilog of B<ex_try> to perform additional
 operations at the new (restored) machine context after an exception was
 caught. Usually this is a no-operation macro.
 
-=item B<__ex_mctx_restore>(I<mctx>)
+=item B<__ex_mctx_restore>(__ex_mctx_struct *I<mctx>)
 
 This is called by B<ex_throw> at the old machine context in order to
 restore the machine context of the B<ex_try>/B<ex_catch> clause which
@@ -263,66 +270,69 @@
 
 =back
 
-The default implementation (define C<__EX_MCTX_USE_SJLJ__> or as long
-C<__EX_MCTX_USE_CUSTOM__> is not defined) uses B<ISO-C> jmp_buf(3):
+The default implementation (define C<__EX_MCTX_SJLJ__> or as long
+C<__EX_MCTX_CUSTOM__> is not defined) uses the B<ISO-C> jmp_buf(3)
+facility:
 
  #define __ex_mctx_struct         jmp_buf jb;
  #define __ex_mctx_save(mctx)     (setjmp((mctx)->jb) == 0)
  #define __ex_mctx_restored(mctx) /* noop */
  #define __ex_mctx_restore(mctx)  (void)longjmp((mctx)->jb, 1)
 
-Alternatively one can define C<__EX_MCTX_USE_SSJLJ__> to use B<POSIX.1>
-sigjmp_buf(3) and C<__EX_MCTX_USE_MCSC__> to use B<POSIX.1> ucontext(3).
-For using a custom implementation define C<__EX_MCTX_USE_CUSTOM__> and
-provide own macro definitions for the four B<__ex_mctx_xxxx>.
+Alternatively, you can define C<__EX_MCTX_SSJLJ__> to use B<POSIX.1>
+sigjmp_buf(3) or C<__EX_MCTX_MCSC__> to use B<POSIX.1> ucontext(3). For
+using a custom implementation define C<__EX_MCTX_CUSTOM__> and provide
+own definitions for the four B<__ex_mctx_xxxx> macros.
 
 =head2 Exception Context
 
 In order to maintain the exception catching stack and for passing the
 exception between the throw and the catch point, B<OSSP ex> uses a
-global exception context, returned on-the-fly by the callback "ex_ctx_t
-*(*B<__ex_ctx>)(void)".
+global exception context, returned on-the-fly by the callback "C<ex_ctx_t
+*(*>B<__ex_ctx>C<)(void)>".
 
-The default B<__ex_ctx> (B<__ex_ctx_default> as provided by F<libex>)
-returns a pointer to a static B<ex_ctx_t> context. For use in
-multi-threading environments, this should be overwritten with a
-per-thread context structure.
+By default, B<__ex_ctx> (which is B<__ex_ctx_default> as provided by
+F<libex>) returns a pointer to a static C<ex_ctx_t> context. For use in
+multi-threading environments, this should be overwritten with a callback
+function returning a per-thread context structure.
 
 To initialize an exception context structure there are two macros
-defined: B<EX_CTX_INITIALIZER> for static initialization and
-B<EX_CTX_INITIALIZE>(B<ex_ctx_t *>I<ctx>) for dynamic initialization.
+defined: "B<EX_CTX_INITIALIZER>" for static initialization and
+"C<void >B<EX_CTX_INITIALIZE>C<(ex_ctx_t *)>" for dynamic
+initialization.
 
 =head2 Termination Handler
 
 In case there is an exception thrown which is not caught by any
-B<ex_try>/B<ex_catch> clauses, B<OSSP ex> calls the callback "void
-(*B<__ex_terminate>)(C<ex_t *>)". It receives a pointer to the exception
-object which should have been thrown.
-
-The default B<__ex_terminate> (B<__ex_terminate_default> as provided by
-F<libex>) this prints a message of the form "C<**EX: UNCAUGHT EXCEPTION:
-class=0xXXXXXXXX object=0xXXXXXXXX value=0xXXXXXXX [file:123:func]>" to
-F<stderr> and then calls abort(3) in order to terminate the application.
-For use in multi-threading environments, this should be overwritten with
-a callback function which terminates only the current thread.
+B<ex_try>/B<ex_catch> clauses, B<OSSP ex> calls the callback "C<void
+(*>B<__ex_terminate>C<)(ex_t *)>". It receives a pointer to the
+exception object which should have been thrown.
+
+By default, B<__ex_terminate> (which is B<__ex_terminate_default>
+as provided by F<libex>) prints a message of the form "C<**EX:
+UNCAUGHT EXCEPTION: class=0xXXXXXXXX object=0xXXXXXXXX value=0xXXXXXXX
+[xxxx:NNN:xxxx]>" to F<stderr> and then calls abort(3) in order to
+terminate the application. For use in multi-threading environments, this
+should be overwritten with a callback function which terminates only the
+current thread.
 
 =head2 Namespace Mapping
 
-B<OSSP ex> implementation consistently uses the B<ex_>, B<__ex_>
-and B<__EX_> prefixes for namespace protection. But at least the
-B<ex_> prefix for the API macros B<ex_try>, B<ex_cleanup>, B<ex_catch>,
-B<ex_throw>, B<ex_rethrow> and B<ex_shield> sometimes have a unpleasant
-optical appearance. Especially because B<OSSP rc> is modeled after the
-exception facility in B<ISO-C++> where there is no such prefix on the
-directives.
-
-For this B<OSSP ex> optionally provides the ability to provide
-additional namespace mappings for those API macros. By default (define
-C<__EX_NS_USE_CXX__> or as long as C<__EX_NS_USE_CUSTOM__> and
-C<__cplusplus> is not defined) you can additional C++ style macros
-named B<catch>, B<cleanup>, B<throw>, B<rethrow> and B<shield>. As an
-alternative you can define C<__EX_NS_USE_UCCXX__> to get the same but
-with an (more namespace safe) upper case first letter.
+The B<OSSP ex> implementation consistently uses the "C<ex_>", "C<__ex_>"
+and "C<__EX_>" prefixes for namespace protection. But at least
+the "C<ex_>" prefix for the API macros B<ex_try>, B<ex_cleanup>,
+B<ex_catch>, B<ex_throw>, B<ex_rethrow> and B<ex_shield> sometimes have
+an unpleasant optical appearance. Especially because B<OSSP ex> is
+modeled after the exception facility of B<ISO-C++> where there is no
+such prefix on the language directives, of course.
+
+For this, B<OSSP ex> optionally provides the ability to provide
+additional namespace mappings for those API elements. By default (define
+C<__EX_NS_CXX__> or as long as C<__EX_NS_CUSTOM__> and C<__cplusplus>
+is not defined) you can additionally use the B<ISO-C++> style names
+B<catch>, B<cleanup>, B<throw>, B<rethrow> and B<shield>. As an
+alternative you can define C<__EX_NS_UCCXX__> to get the same but with a
+more namespace safe upper case first letter.
 
 =head1 MULTITHREADING ENVIRONMENTS
 
@@ -331,26 +341,29 @@
 only. But it is easy to configure B<OSSP ex> to work correctly in a
 multi-threading environment like B<POSIX pthreads> or B<GNU pth>.
 
-There are two issues: which machine context to use and where to
+There are only two issues: which machine context to use and where to
 store the exception context to make sure exception throwing happens
 only within a thread and does not conflict with the regular thread
-dispatching.
+dispatching mechanism.
 
 =head2 GNU pth
 
-Using B<OSSP ex> with B<GNU pth> is straight-forward, because B<GNU pth>
-1.5 (or higher) already has support for B<OSSP ex> built-in. All which
-is needed is that B<GNU pth> is configured with the Autoconf option
-C<--with-ex>. Then each thread has its own B<OSSP ex> exception context.
+Using B<OSSP ex> together with B<GNU pth> is straight-forward, because
+B<GNU pth> 1.5 (and higher) already has support for B<OSSP ex> built-in.
+All which is needed is that B<GNU pth> is configured with the B<GNU
+Autoconf> option C<--with-ex>. Then each B<GNU pth> user-space thread
+has its own B<OSSP ex> exception context automatically. The default
+of using B<ISO-C> jmp_buf(3) does not conflict with the thread
+dispatching mechanisms used by B<GNU pth>.
 
 =head2 POSIX pthreads
 
-Using B<OSSP ex> inside a standard B<POSIX pthreads> environment is
-also straight-forward, although it requires additional coding. What
-you basically have to do is to make sure that the B<__ex_ctx> becomes
-a per-thread context and that B<__ex_terminate> terminates only the
-current thread. To get an impression, a small utility library for this
-follows:
+Using B<OSSP ex> inside an arbitrary B<POSIX pthreads> standard
+compliant environment is also straight-forward, although it requires
+extra coding. What you basically have to do is to make sure that the
+B<__ex_ctx> becomes a per-thread context and that B<__ex_terminate>
+terminates only the current thread. To get an impression, a small
+utility library for this follows:
 
 =over 4
 
@@ -362,7 +375,7 @@
 #include <pthread.h>
 
 int pthread_init_ex   (void);
-int pthread_create_ex (pthread_t *thread, const pthread_attr_t *attr, void *(*entry)(void *), void *arg);
+int pthread_create_ex (pthread_t *, const pthread_attr_t *, void *(*)(void *), void *);
 
 #ifndef PTHREAD_EX_INTERNAL
 #define pthread_init   pthread_init_ex
@@ -451,13 +464,13 @@
 
 =back
 
-Now all which is required is that you include F<pthread_ex.h> after
-the standard F<pthread.h> header and to call B<pthread_init>() once at
-startup of your program.
+Now all which is required is that you include F<pthread_ex.h> after the
+standard F<pthread.h> header and to call B<pthread_init> once at startup
+of your program.
 
 =head1 EXAMPLES
 
-As a full real-life example we will look how you can add optional B<OSSP
+As a real-life example we will look how you can add optional B<OSSP
 ex> based exception handling support to a library B<foo>. The original
 library looks like this:
 
@@ -555,72 +568,49 @@
 =item F<foo.h>
 
  ...
- foo_rc_t foo_ex(foo_t *foo, int use);
+ extern const char foo_id[];
  ...
 
 =item F<foo.c>
 
  #include "foo.h"
 
+ const char foo_id[] = "foo 1.0";
+ 
  #ifdef WITH_EX
  #include "ex.h"
- char foo_ex_class = "foo"; /* class identifier */
- int  foo_ex_use   = 0;     /* class disable flag */
+ #define FOO_RC(rv) \
+     (  (rv) != FOO_OK && (ex_catching && !ex_shielding) \
+      ? (ex_throw(foo_id, NULL, (rv)), (rv)) : (rv) )
+ #else
+ #define FOO_RC(rv) (rv)
  #endif
- 
+
  struct foo_st {
- #ifdef WITH_EX
-     int ex_use; /* object disable flag */
- #endif
      ...
  }
 
- #ifdef WITH_EX
- #define FOO_ERR(ctx,err) \
-     ((   ex_shielding \
-       || !foo_ex_use \
-       || ((ctx) != NULL && !(ctx)->ex_use)) 
-      ? FOO_ERR_##err \
-      : ex_throw(&foo_ex_class, ctx, FOO_ERR_##err))
- #else
- #define FOO_ERR(ctx,err) \
-      (FOO_ERR_##err)
- #endif
-
  foo_rc_t foo_create(foo_t **foo)
  {
      if ((*foo = (foo_t)malloc(sizeof(foo))) == NULL)
-         return FOO_ERR(NULL, SYS);
-     (*foo)->ex_use = 0;
+         return FOO_RC(FOO_ERR_SYS);
      (*foo)->... = ...
      return FOO_OK;
  }
 
- foo_rc_t foo_ex(foo_t *foo, int use)
- {
-     if (foo == NULL)
-         return FOO_ERR(foo, ARG);
-#ifndef WITH_EX
-     return FOO_ERR_IMP;
-#else
-     foo->ex_use = use;
-     return FOO_OK;
-#endif
- }
-
  foo_rc_t foo_perform(foo_t *foo)
  {
      if (foo == NULL)
-         return FOO_ERR(foo, ARG);
+         return FOO_RC(FOO_ERR_ARG);
      if (...)
-         return FOO_ERR(foo, XXX);
+         return FOO_RC(FOO_ERR_XXX);
      return FOO_OK;
  }
 
  foo_rc_t foo_destroy(foo_t *foo)
  {
      if (foo == NULL)
-         return FOO_ERR(foo, ARG);
+         return FOO_RC(FOO_ERR_ARG);
      free(foo);
      return FOO_OK;
  }
@@ -628,29 +618,30 @@
 =back
 
 This way the library by default is still exactly the same. If you now
-compile it with C<-DWITH_EX> you build optional exception handling
-support into it, although it is still disabled and the library behaviour
-is the same. But if you now enable execptions via C<foo_ex(foo, 1);>
-the library throws exceptions where C<ex_value> is the C<foo_rc_t>
-instead of returning this value. Notice that in our example we allow the
-enabling/disabling also on a per object basis, i.e., some B<foo> objects
-could have exception handling enabled and others not.
+compile it with C<-DWITH_EX> you activate exception handling support.
+This means that all API functions throw exceptions where C<ex_value> is
+the C<foo_rc_t> instead of returning this value.
 
 =head1 SEE ALSO
 
-C++ try/catch/throw language directives;
-setjmp(3), longjmp(3), sigsetjmp(3), siglongjmp(3).
+B<ISO-C++> C<try>/C<catch>/C<throw>;
+B<Java> C<try>/C<catch>/C<finally>/C<throw>;
+B<ISO-C> jmp_buf(3)/setjmp(3)/longjmp(3);
+B<POSIX.1> sigjmp_buf(3)/sigsetjmp(3)/siglongjump(3);
+B<POSIX.1> ucontext(3)/setcontext(3)/getcontext(3).
 
 =head1 HISTORY
 
-B<OSSP ex> was invented in January 2002 by Ralf S. Engelschall for use
-inside the OSSP project. Its creation was prompted by the requirement
-to reduce the error handling inside B<OSSP lmtp2nntp>. The core
-B<try>/B<catch> clause is inspired by B<ISO-C++> and the implementation
-is derived from B<cexcept> 2.0.0, a similar library written 2000
-by Adam M. Costello E<lt>amc@cs.berkeley.eduE<gt> and Cosmin Truta
-E<lt>cosmin@cs.toronto.eduE<gt>. The B<cleanup> clause is inspired by
-the B<Java> C<finally> clause.
+B<OSSP ex> was invented in January 2002 by Ralf S. Engelschall
+E<lt>rse@engelschall.comE<gt> for use inside the B<OSSP> project.
+Its creation was prompted by the requirement to reduce the error
+handling inside B<OSSP lmtp2nntp>. The core B<try>/B<catch> clause
+was inspired by B<ISO-C++> and the implementation was partly
+derived from B<cexcept> 2.0.0, a similar library written 2000 by
+Adam M. Costello E<lt>amc@cs.berkeley.eduE<gt> and Cosmin Truta
+E<lt>cosmin@cs.toronto.eduE<gt>. The B<cleanup> clause was inspired by
+the B<Java> C<finally> clause. The B<shield> feature was inspired by an
+C<errno> shielding facility used in the B<GNU pth> implementation.
 
 =head1 AUTHORS
 

CVSTrac 2.0.1