/* StackFrame.m * * Copyright Niels Möller 1995 * * Freely distributable under the terms and conditions of the * GNU General Public License. */ #include #include #include /* I'm not sure if I should hardcode StackFrame here or not. */ #ifndef FRAME_STACK #define FRAME_STACK [self class] #endif FRAME_STACK /* The only reason the_frame_stack is not declared static, is to be * compatible with C programs using the macros in catch.h . */ struct frame_stack the_frame_stack; /* For compatibility with catch.c */ void init_catch(void) { /* Call a dummy method, to make sure that the class is initialized */ [StackFrame c_init]; } static int initialization_done = 0; static void out_of_memory(void) { [[[ErrorNoMemory alloc] message: "frame_stack: not enough memory" freeIt: NO] raise]; } static void catch_on_exit(void) { frstack_unwind(&the_frame_stack, NULL); obstack_free(&(the_frame_stack.ob), NULL); } static int cmp_match(frame_id frame, void *data) { return (frame->type == frstack_catch_object) && [( (struct frstack_catch_object_frame *)frame)->object matches: (id) data]; } @implementation StackFrame + initialize { /* Make sure we only initialize once */ if (!initialization_done) { frstack_init(&the_frame_stack); if (atexit(catch_on_exit) != 0) return [self error: "atexit() failed!"]; the_frame_stack.on_error = out_of_memory; initialization_done = 1; } return self; } + (void) c_init { return; } /* Makes sure the class is * properly initialized. */ + (frame_id) pushCatch: object { return fr_catch_object_setup(&the_frame_stack, object); } + (frame_id) pushProtect: reciever send: (SEL) selector { return fr_protect_object(&the_frame_stack, reciever, selector); } + (frame_id) pushProtectCall: (void (*)(void)) function { return fr_protect_fn0(&the_frame_stack, function); } + (frame_id) pushProtectCall: (void (*)(void *)) function with: (void *) arg { return fr_protect_fn1(&the_frame_stack, function, arg); } + (frame_id) findFrameMatching: object { return frstack_find_frame(&the_frame_stack, cmp_match, (void *) object); } + (void) unwind: (frame_id) fr { frstack_unwind(&the_frame_stack, fr); } + (void) freeFrame: (frame_id) fr { frstack_free(&the_frame_stack, fr); } - free { if (frame) [self cleanup]; return [super free]; } - rawFree { return [super free]; } - (void) cleanup { if (frame) [FRAME_STACK freeFrame: frame]; frame = NULL; } - (BOOL) matches: tag { [self subclassResponsibility: @selector(matches)]; return NO; /* Not reached */ } @end /* StackFrame */