/* 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 reason the_frame_stack is not declared static, is to be * compatible with the macros in ccatch.h . */ struct frame_stack the_frame_stack; /* This error is raised by new xmalloc if memory allocation fails. */ id xmalloc_error = nil; /* Global data */ static int initialization_done = 0; static int cleanup_on_exit = 0; static id out_of_memory_error = nil; /* For compatibility with ccatch.c */ void init_catch(void) { /* Call a dummy method, to make sure that the class is initialized */ [StackFrame c_init]; } /* Private functions */ static void catch_on_exit(void) { if (cleanup_on_exit) { frstack_unwind(NULL, 1); frstack_free(NULL); #if 0 obstack_free(&(the_frame_stack.ob), NULL); #endif } } 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]; } static void out_of_memory(void) { if (out_of_memory_error) [out_of_memory_error raise]; fprintf(stderr,"StackFrame: Out of memory\n"); } @implementation StackFrame + initialize { /* Make sure we only initialize once */ if (!initialization_done) { frstack_init(); if (atexit(catch_on_exit) != 0) return [self error: "atexit() failed!"]; out_of_memory_error = [OutOfMemory newMessage: "StackFrame: Out of memory"]; xmalloc_error = [OutOfMemory newMessage: "xmalloc: Virtual memory exhausted"]; the_frame_stack.on_error = out_of_memory; cleanup_on_exit = YES; initialization_done = 1; } return self; } + cleanupOnExit: (BOOL) flag { cleanup_on_exit = flag; return self; } + (void) c_init { return; } /* Makes sure the class is * properly initialized. */ + (frame_id) pushCatch: object { return fr_catch_object_setup(object); } + (frame_id) pushCleanupSending: (SEL) selector to: reciever { return fr_cleanup_object(reciever, selector); } + (frame_id) pushCleanupCall: (void (*)(void)) function { return fr_cleanup_fn0(function); } + (frame_id) pushCleanupCall: (void (*)(void *)) function with: (void *) arg { return fr_cleanup_fn1(function, arg); } + (frame_id) pushCleanup_jmp { return fr_cleanup_jmp_setup(); } + (void) unwindContinue: (frame_id) target { frstack_continue(target); } + (frame_id) findFrameMatching: object; { return frstack_find_frame(cmp_match, (void *) object); } + (void) unwind: (frame_id) target pleaseReturn: (BOOL) flag { frstack_unwind(target, flag); } + (void) freeFrame: (frame_id) fr { frstack_free(fr); } + (void) jumpToFrame: (frame_id) target { frstack_jmp(target); } - free { if (frame) [self cleanup]; return [super free]; } - rawFree { return [super free]; } - (void) cleanup { if (frame) [FRAME_STACK freeFrame: frame]; frame = NULL; } - (BOOL) matches: object { [self subclassResponsibility: @selector(matches)]; return NO; /* Not reached */ } @end /* StackFrame */