// Controller extensions for CrashCatcher -- Peter Camps -- Aug 94 // // This Controller category initializes and configures crashcatcher to // obtain the following behavior : // - when the first crash occurs : // - generate a report on the console, and optionally in a compose window // - alert the user, and offer a chance to recover and try to save work // - if requested, restart the application's main event loop // - when a second crash occurs, immediately quit to avoid indefinite loops // // $Id: ControllerCC.m,v 1.1.1.1 2003/04/24 08:21:01 chuck Exp $ #import #import #import "ControllerCC.h" @implementation Controller(CrashCatcher) // ** General // This class variable becomes YES after the first crash report has been output static BOOL hasCrashed = NO; // This signal handler intercepts signals to add custom behavior static void my_signal_handler(int aSignal) { // quit if this is not the first crash if (hasCrashed) exit(1); // remove the block on a reoccurrence of the signal we're handling sigsetmask(0); // let crashcatcher handle the signal cc_trap_signal(aSignal); } // ** Initialization // This method is called from appWillInit in the main Controller category // to setup & configure CrashCatcher - CC_setup; { // Initialize & activate CrashCatcher [CrashCatcher CC_setup]; // Configure CrashCatcher to handle exceptions as well [CrashCatcher CC_resumeHandlingExceptions]; // Install custom signal handler cc_setup_signal_traps((SigHandlerProc) my_signal_handler); // Turn on email (if requested) and set the target email address [self CC_setupMailAddress]; // Set CrashCatcher's delegate to self [CrashCatcher CC_setDelegate:self]; return self; } // Turn on email (if requested) and set the target email address - CC_setupMailAddress; { const char *mail = DiagnosticsMail; // retrieve address from preferences [CrashCatcher CC_setMailAddress:(*mail ? mail : NULL)]; [CrashCatcher CC_addDestination:SRD_MailApp] return self; } // ** CrashCatcher delegate methods // The string returned by this method will be used as the subject for // the mail message that contains the CrashCatcher state snapshot report. - (const char *)CC_reportSubject { return "CrashCatcher Report from Tailor"; } // The string returned by this method will be included in each crash report static char signature[40]; - (const char *)CC_applicationSignature { if (hasCrashed) exit(1); // quit if generating second report strcpy(signature, "Tailor "); strcat(signature, [self versionString]); #ifdef DEBUG strcat(signature, " (built for DEBUG)"); #endif return signature; } // This method is called after a crash report has been output. The first time, // we warn the user and give him a chance to try and recover from the crash. - CC_didOutputReport:(const char *)outBuf { if (!hasCrashed) { // only for the first crash report int recover; const char *report = *(DiagnosticsMail) ? "prepared ready to be mailed" : "written to the console"; // remember that we have crashed at least once hasCrashed = YES; // ask the user if he wants a chance NXBeep(); recover = NXRunAlertPanel("Fatal Error", "A fatal internal error has occurred " "(an error report has been %s). " "Try to save your work and quit !", "Give me a chance", "Quit now anyway", NULL, report); } // restart the application if so requested if (recover == NX_ALERTDEFAULT) [NXApp run]; else exit(1); // or else simply quit return self; // to satisfy compiler } // This method is called before a crash report will be output. // We refuse to generate anything after the first report. - CC_didGenerateReport:(const char *)outBuf { if (hasCrashed) exit(1); // quit if generating second report return self; } @end