/* ccatch.h
 *
 * C-interface to catch, throw and unwind-protect like facilities.
 *
 * Copyright Niels Möller <nisse@lysator.liu.se> 1995
 *
 * Freely distributable under the terms and conditions of the
 * GNU General Public License.
 */

#ifndef CCATCH_H_INCLUDED
#define CCATCH_H_INCLUDED

#include <frame_stack.h>

#define catch_tag frame_id
#define protect_tag frame_id

void
init_ccatch(void);

extern int
ccatch_cleanup_on_exit;

/* Usage:
 *
 * catch_id tag;
 *
 * C_STARTCATCH(tag)
 *
 * ... body ...
 *
 * C_CATCH(tag)
 *
 * ... handler ...
 *
 * C_ENDCATCH(tag)
 *
 *
 * The statements between C_CATCH and C_ENDCATCH are executed if a
 * throw happens while the body is executing. The variable result (an
 * int) holds the result passed with this throw.
 *
 * C_CATCH and the handler are optional, but if you omit them,
 * there's (currently) no way to find out if a throw occured.
 */

#define C_STARTCATCH(tag) \
{ \
    int result; \
    (tag) = fr_ccatch_setup(); \
    if ((result = SETJMP(( (struct frstack_ccatch_frame *) \
			   (tag) )->where)) == 0) \
       {
	   
#define C_CATCH(tag) } else {
  
#define C_ENDCATCH(tag) } frstack_free(tag); }

/* Usage:
 *
 * C_THROW(tag, value);
 *
 * Passes control to the C_CATCHSTART that created the tag.
 */

#define C_THROW(tag, value) fr_cthrow((tag), (value))

/* Usage:
 *
 * protect_id tag
 * C_PROTECTSTART(tag)
 *
 * ... body ...
 *
 * C_CLEANUP(tag)
 *
 * ... cleanup statements ...
 *
 * C_END_PROTECT(tag)
 *
 *
 * The cleanup statements will be executed when the body terminates
 * no matter if it is simply finished or a throw or an error occurs.
 */

#ifndef NO_LOCAL_FUNCTIONS

#define C_UNWINDPROTECT(tag, body, cleanup_code) {\
  void __C_UNWINDPROTECT_cleanup_fn(void) cleanup_code \
  (tag) = fr_cleanup_fn0(__C_UNWINDPROTECT_cleanup_fn); \
  body \
  __C_UNWINDPROTECT_cleanup_fn(); \
  frstack_free(tag); \
}

#else NO_LOCAL_FUNCTIONS

#define C_UNWINDPROTECT(tag, body, cleanup_code) {\
  (tag) = fr_cleanup_jmp_setup(); \
  if (SETJMP(( (struct fr_stack_cleanup_jmp_frame *) (tag))->where)==0) \
    body \
  cleanup_code \
  frstack_free(tag) \
}

#endif NO_LOCAL_FUNCTIONS


#define C_PROTECTSTART(tag) \
{ \
    int result; \
    (tag) = fr_cleanup_jmp_setup(); \
    if ((result = SETJMP(( (struct frstack_cleanup_jmp_frame *) \
			   (tag) )->where)) == 0) \
       {

#define C_CLEANUP(tag) }

#define C_ENDPROTECT(tag) frstack_continue(tag); frstack_free(tag); }

#endif CCATCH_H_INCLUDED
