This is MaskedException.m in view mode; [Download] [Up]
/* MaskedException - Allow masking of exceptions. Copyright (C) 1995, Adam Fedor. */ #ifdef NEXT_FOUNDATION #import <foundation/NSDictionary.h> #import <foundation/NSString.h> #import <foundation/NSValue.h> #import <foundation/NSUtilities.h> #else #import <Foundation/NSDictionary.h> #import <Foundation/NSString.h> #import <Foundation/NSValue.h> #import <Foundation/NSUtilities.h> #endif #include "MathArray/MaskedException.h" #include <stdio.h> typedef struct { ExceptionMask e_mask; id <MaskedExceptionHandling> handler; } mask_info_t; static NSMutableDictionary *exceptions; static NSMutableDictionary *prefixes; static mask_info_t global_mask = {RaiseException, nil}; @implementation MaskedException /* This is a simple class that allows one to control the effects of raised exceptions. Perhaps one of the best uses of this class is for debugging. If an exception occurs during debugging, the program aborts (unless the exception is caught), but in any case, the original context of the error is completely lost, making it difficult to trace the cause of the error. With MaskedException, you can cause the exception to abort the program in place, without jumping out of the context, so you can go back and look for at the frame that caused the error. You can set a mask for one exception or a whole class of excetions using MaskedExcetion. The set of choices (masks) includes: .LI .ital RaiseException .plain Normal operation. Raise the exception as usual. .LI .ital AbortException .plain Abort, rather than raise the exception. Prints a message to stderr. .LI .ital HandleException .plain Sends a message to a specific exception handler object. .LI .ital LogException .plain Log the exception (NSLog) and continue excecution. Dangerous! .LI .ital IgnoreException .plain Completely ignore the exception and continue excecution. Dangerous! Note the last two choices, which allow one to completely ignore the exception and continue as if nothing happened. Normally, this is not very useful and would probably cause some kind of program crash, but it could be used in cases where an exception is meant to be a warning rather than an error. The third choice allows one to set a specific handler object to handle one or more exceptions. When the exception is raised, the message .bold exceptionWithName:reason:userInfo .plain is sent to the object (like the NSException method of the same name). */ /* Easy way to get MaskedException to work with all exceptions (same as [self poseAsClass:[NSException class]]). */ + (void)bodysnatchNSException { [self poseAsClass:[NSException class]]; } + (void)_updateLazyVariables { if (!exceptions) exceptions = [NSMutableDictionary dictionaryWithCapacity:2]; if (!prefixes) prefixes = [NSMutableDictionary dictionaryWithCapacity:2]; } /* Set the handler object for exceptions with the name exceptionName. */ + (void)setHandler: (id <MaskedExceptionHandling>)handler forException:(NSString *)exceptionName { NSValue *info; mask_info_t mask_info; if (!exceptionName) return; [self _updateLazyVariables]; mask_info.e_mask = HandleException; mask_info.handler = handler; info = [NSValue value:&mask_info withObjCType:@encode(mask_info_t)]; [exceptions setObject:info forKey:exceptionName]; } /* Set the handler object for any exception with a name that has the prefix prefix. */ + (void)setHandler:(id <MaskedExceptionHandling>)handler forExceptionsWithPrefix:(NSString *)prefix { NSValue *info; mask_info_t mask_info; if (!prefix) return; [self _updateLazyVariables]; mask_info.e_mask = HandleException; mask_info.handler = handler; info = [NSValue value:&mask_info withObjCType:@encode(mask_info_t)]; [prefixes setObject:info forKey:prefix]; } /* Set the default handler object for all exceptions. */ + (void)setHandlerForAllExceptions:(id <MaskedExceptionHandling>)handler { global_mask.e_mask = HandleException; global_mask.handler = handler; } /* Set the mask for exceptions with the name exceptionName. */ + (void)setMask:(ExceptionMask)mask forException:(NSString *)exceptionName { NSValue *info; mask_info_t mask_info; if (!exceptionName) return; [self _updateLazyVariables]; mask_info.e_mask = mask; info = [NSValue value:&mask withObjCType:@encode(mask_info_t)]; [exceptions setObject:info forKey:exceptionName]; } /* Set the mask for any exception with a name that has the prefix prefix. */ + (void)setMask:(ExceptionMask)mask forExceptionsWithPrefix:(NSString *)prefix { NSValue *info; mask_info_t mask_info; if (!prefix) return; [self _updateLazyVariables]; mask_info.e_mask = mask; info = [NSValue value:&mask_info withObjCType:@encode(mask_info_t)]; [prefixes setObject:info forKey:prefix]; } /* Set the default mask for all exceptions. */ + (void)setMaskForAllExceptions:(ExceptionMask)mask { global_mask.e_mask = mask; } + (mask_info_t)maskInfoForException:(NSString *)exceptionName { NSValue *info; mask_info_t mask_info; if (!exceptionName) return ((mask_info_t){0, 0}); [self _updateLazyVariables]; mask_info = global_mask; if ((info = [exceptions objectForKey:exceptionName])) [info getValue:&mask_info]; else { NSEnumerator *enumerator = [prefixes keyEnumerator]; NSString *prefix = nil; while ((prefix = [enumerator nextObject])) if ([exceptionName hasPrefix:prefix]) break; else prefix = nil; if (prefix) { info = [prefixes objectForKey:prefix]; [info getValue:&mask_info]; } } return mask_info; } /* Returns the mask for the exception with name exceptionName if is was explicitly set, or the mask for the set of exception names that have the same prefix as exceptionName. Otherwise returns the global exception mask (RaiseException by default) set by setMaskForAllExceptions. */ + (ExceptionMask)maskForException:(NSString *)exceptionName { return ([self maskInfoForException:exceptionName]).e_mask; } /* Override from NSException to do the right thing */ - (volatile void)raise { NSString *raise_name; NSString *raise_reason; NSDictionary *raise_info; mask_info_t mask_info; static BOOL did_raise; /* Prevent us from doing something stupid like causing an exception in the middle of our own exception handling */ if (did_raise) { did_raise = NO; [super raise]; } did_raise = YES; #ifdef NEXT_FOUNDATION raise_name = [self exceptionName]; raise_reason = [self exceptionReason]; raise_info = [self exceptionUserInfo]; #else raise_name = [self name]; raise_reason = [self reason]; raise_info = [self userInfo]; #endif mask_info = [MaskedException maskInfoForException:raise_name]; did_raise = NO; switch (mask_info.e_mask) { case RaiseException: [super raise]; break; case AbortException: // FIXME: where should we print the information? stderr I assume. fprintf(stderr, "Aborted Exception %s: %s\n", [raise_name cString], [raise_reason cString]); abort(); break; case HandleException: [mask_info.handler exceptionWithName:raise_name reason:raise_reason userInfo:raise_info]; break; case LogException: // FIXME: should be NSLog //NSLog(@"Ignored Exception %@: %@\n", raise_name, raise_reason); fprintf(stderr, "Ignored Exception %s: %s\n", [raise_name cString], [raise_reason cString]); break; case IgnoreException: break; } // FIXME: The last two cases actually return when the method is assumed // not to return. How useful are these cases? } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.