/* UnwindProtect.h       -*-objc-*-
 *
 * Copyright Niels Möller <nisse@lysator.liu.se> 1995
 *
 * Freely distributable under the terms and conditions of the
 * GNU General Public License.
 */

#ifndef UNWINDPROTECT_H_INCLUDED
#define UNWINDPROTECT_H_INCLUDED

#include <StackFrame.h>
#include <Catch.h>

/* NOTE: Cleanup actions registered with cleanupByJumpingHere 
 * will *not* be called automatically if the program exit()s, nor
 * as a result of a cleanup message. */

/* UnwindProtect
 * -------------
 *
 * id tag = [UnwindProtect new];
 *
 * [tag cleanupByCalling: someFunction];
 * [tag cleanupByCalling: someFunction with: argument];
 * [tag cleanupBySending: someSelector to: someObject];
 * if (set_catch([tag cleanupByJumpingHere]))
 * {
 *    ... cleanup code ...
 *    [tag continue];
 * }
 * else
 * {
 *    ... body ...
 *
 * }
 *
 * [tag cleanup];
 *
 * Any number of cleanup actions are allowed.
 */

@interface UnwindProtect : StackFrame

/* By default, freeing this object itself is done automatically when
 * cleaning up. If you don't want this, use
 * [[UnwindProtect alloc] initDontFree] instead of [UnwindProtect new].
 */
 
- initDontFree;
- cleanupByCalling: ( void (*)(void)) function;
- cleanupByCalling: ( void (*)(void *)) function with: (void *) argument;
- cleanupBySending: (SEL) message to: rec;
- (JMP_BUF *) cleanupByJumpingHere: (frame_id *) framepointer;
- (void) cleanup;
@end

#ifndef NO_LOCAL_FUNCTIONS

#define UNWINDPROTECT(tag, body, cleanup_code) {\
  void __UNWINDPROTECT_cleanup_fn(void) cleanup_code \
  (tag) = [UnwindProtect new]; \
  [tag cleanupByCalling: __UNWINDPROTECT_cleanup_fn];\
  body \
  [tag cleanup]; }

#else NO_LOCAL_FUNCTIONS

#define UNWINDPROTECT(tag, body, cleanup_code) {\
  frame_id __UNWIND_PROTECT_frame; \
  [tag new]; \
  if (SETJMP([tag cleanupByJumpingHere: &__UNWIND_PROTECT_frame])==0) \
    body \
  cleanup_code \
  [[tag class] unwindContinue: __UNWIND_PROTECT_frame];
  [tag cleanup]; \
}	  

#endif NO_LOCAL_FUNCTIONS

#endif UNWINDPROTECT_H_INCLUDED
