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.