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