This is EMErrorManager.m in view mode; [Download] [Up]
#import "EMErrorManager.h" #import "EMErrorObserver.h" #import "EMErrorDescription.h" #import "EMObjcErrorCatcher.h" #import "localizable_strings.h" #import <appkit/appkit.h> #define ALIGNMENT(type) (offsetof(struct { char c; type t; },t)) @implementation EMErrorManager static id theEMErrorManager = nil; //-------------------------------------------------------------------------------- // HILFSFUNKTIONEN // Die ErrorReporter und -handler Funktionen, SignalHandler //-------------------------------------------------------------------------------- static void EMErrorReporter(NXHandler *errorState) { EMErrorInfo *ex=(id)errorState->data1; NXLogError("EMErrorReporter: %s: #%d\n",[ex location],[ex code]); } static void EMErrorHandler(NXHandler *errorState) { if(![[EMErrorManager new] handle:EMInfoObjectForHandler(errorState)]) NXDefaultTopLevelErrorHandler(errorState); } static void EMSignalHandler(int signalno) { sigsetmask(0); // unblock all signals... EM_ERROR(EM_SIGBASE+signalno,NULL,NULL); } //-------------------------------------------------------------------------------- // HILFSFUNKTIONEN, Teil 2 //-------------------------------------------------------------------------------- EMErrorInfo *EMInfoObjectForHandler(NXHandler *errorState) { EMErrorInfo *exception; const struct { @defs(EMErrorInfo) } *eip; if(errorState->data1!=NULL && (((int)(errorState->data1))%ALIGNMENT(id))==0 && ((eip=errorState->data1)->code==errorState->code)) exception=(id)errorState->data1; else exception=[[EMErrorInfo newWithCode:errorState->code userInfo:errorState->data1:errorState->data2] getContext]; return exception; } // if(errorState->code>=NX_APP_ERROR_BASE && // errorState->code<NX_APP_ERROR_BASE+EM_ERROR_RANGE) //-------------------------------------------------------------------------------- // HILFSFUNKTIONEN, Teil 3 //-------------------------------------------------------------------------------- /* static void EMFreeValues(void *val) { id v=val; if([v isKindOf:[List class]]) [v freeObjects]; [v free]; } */ //-------------------------------------------------------------------------------- // KLASSENMETHODEN // Sicherstellen, dass nur eine Instanz benutzt wird. //-------------------------------------------------------------------------------- + new { if(!theEMErrorManager) { NXZone *myZone=NXCreateZone(vm_page_size*4,vm_page_size*2,YES); NXNameZone(myZone,"EMErrorManager"); theEMErrorManager=self=[[super allocFromZone:myZone] init]; } else self=theEMErrorManager; return self; } //-------------------------------------------------------------------------------- // INIT & FREE //-------------------------------------------------------------------------------- - init; { [super init]; [self readErrorDescriptions]; objectsToNotify=[[HashTable allocFromZone:[self zone]] initKeyDesc:"i" valueDesc:"@"]; [EMObjcErrorCatcher setup]; [self installErrorReporter:YES]; [self installErrorHandler:YES]; [self installSignalHandler:YES]; return self; } - free; { // [objectsToNotify freeKeys:NULL values:EMFreeValues]; // allgemeines Porblem: wann duerfen die EMErrorObserver freigegeben werden? [objectsToNotify free]; return [super free]; } //-------------------------------------------------------------------------------- // ERROR FILE //-------------------------------------------------------------------------------- - readErrorDescriptions; { return [self readErrorDescriptionsFromBundle:[NXBundle mainBundle]]; } - readErrorDescriptionsFromBundle:(NXBundle *)bundle; { char path[MAXPATHLEN+1]; struct stat buf; NXTypedStream *stream; int vmajor,vemc; HashTable *newTable; NXHashState state; const void *key; EMErrorDescription *ed; NX_DURING [bundle getPath:path forResource:"Errors" ofType:"estore"]; if(strlen(path)<3) NX_RAISE(NX_APP_ERROR_BASE,CANT_LOCATE_MSGS,NULL); else if(stat(path,&buf)) NX_RAISE(NX_APP_ERROR_BASE,CANT_ACCESS_MSGS,NULL); else if(!(buf.st_mode && S_IFREG)) NX_RAISE(NX_APP_ERROR_BASE,CANT_LOCATE_MSGS,NULL); stream=NXOpenTypedStreamForFile(path,NX_READONLY); NXSetTypedStreamZone(stream,[self zone]); NXReadTypes(stream,"ii",&vmajor,&vemc); if(vmajor*100+vemc > EM_MAJOR_VERSION*100+EM_EMC_VERSION) NX_RAISE(NX_APP_ERROR_BASE,MSG_NEW_VERSION,NULL); else if(vmajor*100+vemc < EM_MAJOR_VERSION*100+EM_EMC_VERSION) NX_RAISE(NX_APP_ERROR_BASE,MSG_OLD_VERSION,NULL); newTable=NXReadObject(stream); NXCloseTypedStream(stream); if(errorDescriptions==nil) errorDescriptions=newTable; else { state=[newTable initState]; while([newTable nextState:&state key:&key value:(void *)&ed]) { if([errorDescriptions isKey:key]) NX_RAISE(NX_APP_ERROR_BASE,ERROR_NUMBER_CLASH,NULL); [errorDescriptions insertKey:key value:ed]; } [newTable free]; } NX_HANDLER if([self errorDescriptionFor:EM_INTBASE+2]) EM_ERROR(EM_INTBASE+2,NXLocalHandler.data1,NULL); else { NXRunAlertPanel(INTERNAL_ERROR,CANT_LOAD_MESSAGES,QUIT_BUTTON,NULL,NULL, NXLocalHandler.data1,EM_MAJOR_VERSION,EM_EMC_VERSION); exit(1); } NX_ENDHANDLER return self; } - (HashTable *)errorDescriptions; { return errorDescriptions; } - (EMErrorDescription *)errorDescriptionFor:(int)code; { return (EMErrorDescription *)[errorDescriptions valueForKey:(void *)code]; } //-------------------------------------------------------------------------------- // Handler (de)installieren //-------------------------------------------------------------------------------- - installErrorReporter:(BOOL)flag; { if(flag) NXRegisterErrorReporter(NX_APPBASE,NX_APPBASE+EM_ERROR_RANGE, EMErrorReporter); else NXRemoveErrorReporter(NX_APPBASE); return self; } - installErrorHandler:(BOOL)flag; { if(flag) NXSetTopLevelErrorHandler(EMErrorHandler); else NXSetTopLevelErrorHandler(NXDefaultTopLevelErrorHandler); return self; } - installSignalHandler:(BOOL)flag; { BOOL signals[]={1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,-1}; int i; void (*handler)(int); handler=flag?EMSignalHandler:SIG_DFL; for (i=0;signals[i]!=-1;i++) if(signals[i]) signal(i,handler); return self; } //-------------------------------------------------------------------------------- // Raise Error //-------------------------------------------------------------------------------- - raise:infoObject; { [infoObject getContext]; switch([[self errorDescriptionFor:[infoObject code]] severity]) { case EMSeverityWarning: [self handle:infoObject]; break; case EMSeverityError: NX_RAISE([infoObject code],infoObject,NULL); break; case EMSeverityFatalError: [self handle:infoObject]; exit(2); break; case EMSeverityUnknown: if(([infoObject code])==EM_INTBASE+1) { NXRunAlertPanel(NULL,NO_UNKNOWN_EVEN,QUIT_BUTTON,NULL,NULL, [infoObject codeString]); exit(2); } EM_ERROR(EM_INTBASE+1,(void *)[infoObject code],[infoObject location]); break; } return self; } //-------------------------------------------------------------------------------- // Fehler behandeln //-------------------------------------------------------------------------------- - handle:infoObject; { id ed=[self errorDescriptionFor:[infoObject code]], eo=[objectsToNotify valueForKey:(void *)[infoObject code]]; [self notify:[ed actions] of:infoObject]; [self notify:eo of:infoObject]; [NXApp delayedFree:infoObject]; return ed; } //-------------------------------------------------------------------------------- // Objekte ueber den Fehler benachrichtigen //-------------------------------------------------------------------------------- - notify:obj of:infoObject; { if([obj isKindOf:[List class]]) [obj makeObjectsPerform:@selector(dispatch:) with:infoObject]; else [obj perform:@selector(dispatch:) with:infoObject]; return self; } //-------------------------------------------------------------------------------- // Objekte registrieren, die im Fehlerfall benachrichrichtigt werden //-------------------------------------------------------------------------------- - addObserver:anObject selector:(SEL)aSel forError:(int)errorNumber; { return [self addObserver:anObject selector:aSel forErrors:errorNumber:1]; } - addObserver:anObject selector:(SEL)aSel forErrors:(int)base:(int)count; { id observer,entry; int i; NX_DURING observer=[EMErrorObserver allocFromZone:[self zone]]; [observer initWith:anObject andSelector:aSel]; NX_HANDLER [observer free]; NX_RERAISE(); NX_ENDHANDLER for(i=base;i<base+count;i++) { entry=[objectsToNotify valueForKey:(void *)i]; if(!entry) [objectsToNotify insertKey:(void *)i value:observer]; else if(![entry isKindOf:[List class]]) [objectsToNotify insertKey:(void *)i value:[[[[List allocFromZone:[self zone]] init] addObject:entry] addObject:observer]]; else [entry addObject:observer]; } return self; } - removeObserver:anObject forError:(int)errorNumber { return [self removeObserver:anObject forErrors:errorNumber:1]; } - removeObserver:anObject forErrors:(int)base:(int)count; { id entry; int i,j; for(i=base;i<base+count;i++) { entry=[objectsToNotify valueForKey:(void *)i]; if(!entry) EM_ERROR(EM_INTBASE+12,(void *)i,NULL); else if(![entry isKindOf:[List class]]) if([entry observer]==anObject) [objectsToNotify removeKey:(void *)i]; else EM_ERROR(EM_INTBASE+12,(void *)i,NULL); else { for(j=[entry count]-1;j>=0;j--) if([[entry objectAt:j] observer]==anObject) break; if(j>=0) { [entry removeObjectAt:j]; if([entry count]<2) { [objectsToNotify insertKey:(void *)i value:[entry lastObject]]; [entry free]; } } else EM_ERROR(EM_INTBASE+12,(void *)i,NULL); } } return self; } //-------------------------------------------------------------------------------- // THAT'S IT //-------------------------------------------------------------------------------- @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.