Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
UMAFailure.h
/*[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]*/ |
/* UFailure.p */ |
/* Copyright © 1985-1990 by Apple Computer, Inc. All rights reserved. */ |
/* |
T H E O R Y O F O P E R A T I O N |
This unit implements the MacApp failure mechanism. |
The failure mechanism is built around exception handlers. An exception |
handler is a routine, generally local to some other routine, that is |
called when a failure occurs and takes action to handle the failure. |
An exception handler is of the form |
PROCEDURE ExceptionHandler (error: OSErr; message: LONGINT); |
where error is the error that caused the failure, and message identifies |
the error message that may be displayed. Consider a routine that opens |
a file, reads its contents, and closes the file. If a failure occured |
while reading the file, an exception handler would be needed to close the |
file, as the rest of the routine will not be executed. (See the example |
at the end of these comments.) |
References to expection handlers are defined by the FailInfo record. |
The exception handlers form a linked-list via the nextInfo field of |
FailInfo. The linked list is a stack since new exception handlers |
are added to the front of the list. |
New exception handlers are added to the stack with the CatchFailures |
procedure, and removed from the stack with the Success procedure. In |
general you call CatchFailures to post an exception handler when an |
error the application should handle might occur, and call Success to |
remove the handler from the stack, after the handler is no longer |
needed (i.e. the possibility of error no longer exists). Any failure |
detected within the limits of the CatchFailures and subsequent Success |
call results in the execution of the exception handler. (Failure does |
not have to occur in the same routine as your call to CatchFailures. |
The failure may occur in any routine called after CatchFailures but |
before Success.) |
When MacApp (or your code) determines that a failure has occured, it |
calls Failure. As a convenience, several procedures are provided |
to check for standard kinds of failures and call Failure if needed. |
These procedures are: |
FailNIL Calls Failure if its parameter is NIL. |
FailOSErr Calls Failure if its parameter is not noErr. |
FailMemError Calls Failure if MemError returns other than noErr. |
FailResError Calls Failure if ResError returns other than noErr. |
When Failure is called, execution of the routine that called Failure is |
terminated and the exception handler at the top of the stack is popped. |
For each routine that was called after the handler was posted |
to the stack, execution is terminated as though from an EXIT statement. |
Then the exception handler is called. It generally cleans up for the |
routine in which it is nested. Upon completion the next exception handler |
is popped from the stack, repeating the process. |
The error causing the failure, and a message code is passed to Failure. |
For MacApp, the last exception handler on the stack is the one in |
TApplication.PollEvent. It calls TApplication.ShowError, which calls |
ErrorAlert, which decodes the message and displays an alert. You exception |
handlers may set the message code to one more specific to your application |
by calling FailNewMessage at the end of your exception handler. |
FailNewMessage changes the message only if the current one is non-zero. |
This has the effect of allowing those exception handlers closest to the |
source of the error to set the message. |
One last note about exception handlers: It is possible for an exception |
handler to terminate exception processing by using a non-local GOTO to |
jump back into the routine in which the exception handler is nested. This |
is how MacApp keeps the application running when a failure occurs. The |
last exception handler on the stack, in TApplication.PollEvent, uses a |
GOTO to continue event processing. |
The following is an example showing the use of exception handlers. |
The ReadTheFile procedure reads the contents of a file, signalling |
failure if the open, read, or close returns an error. |
PROCEDURE ReadTheFile (fileName: Str255; volRefNum: INTEGER; |
VAR contents: ContentsRecord); |
VAR |
fi: FailInfo; |
count: LONGINT; |
PROCEDURE ExceptionHandler (error: OSErr; message: LONGINT); |
VAR |
err: OSErr; |
BEGIN |
err := FSClose(fileRefNum); { Make sure the file is closed } |
{ Pass on my own error message... } |
FailNewMessage(error, message, kMyErrorMessage); |
END; |
BEGIN |
{ If FSOpen fails we don't need to do any failure handling, |
though the guy that called us probably will. } |
FailOSErr(FSOpen(fileName, volRefNum, fileRefNum)); |
{ Now that the file is open, if the read fails we must make |
sure to close the file. } |
CatchFailures(fi, Exceptionhandler); |
count := SIZEOF(ContentsRecord); |
FailOSErr(FSRead(fileRefNum, count, @contents)); |
{ The file's been read so we don't need our exception handler |
anymore. } |
Success(fi); |
{ Again, the guy that called us will have to deal with this. } |
FailOSErr(FSClose(fileRefNum)); |
END; |
*/ |
#ifndef __UFailure__ |
#define __UFailure__ 0 |
#endif |
#if ! __UFailure__ |
#define __UFailure__ 1 |
/* ¥ Auto-Include the requirements for this unit's interface. */ |
#ifndef __TYPES__ |
#include "Types.h" |
#endif |
const short minErr = - 32768; /* Low error number */ |
const short maxErr = 32767; /* High error number */ |
/* used for the exception handling mechanism */ |
/* Preferred. The pointer type _MUST_ be declared first |
since the record is self referential */ |
typedef struct FailInfo *FailInfoPtr; |
struct FailInfo { |
long regs[11]; /* The saved registers as of the |
CatchFailures. */ |
short error; /* The error condition passed to Failure. */ |
long message; /* The message which accompanied the Failure. */ |
long failA6; /* A6 of the caller to CatchFailures. */ |
long failPC; /* Address of failure handler routine. */ |
FailInfoPtr nextInfo; /* Next in stack. */ |
}; |
typedef FailInfoPtr PFailInfo; /* Left in for compatibility (2.0) */ |
extern pascal FailInfoPtr gTopHandler; |
/* Most recent link in linked list of failure |
handlers. Set to nil by a constant in |
UFailure.a so that Failure handling never |
needs to be initialized. */ |
extern pascal void Assertion(Boolean condition, StringPtr description); |
/* Asserts a condition.If condition is FALSE : IF debugging : prints description and |
stops in Debugger ELSE : Signals a general failure. */ |
pascal long BuildMessage(short lowWord, short highWord) |
= 0x2E9F; /* MOVE.L (A7)+,(A7) */ |
/* Takes the 2 integers and combines them into a LONGINT failure message. Note that the |
low-order word is the first parameter. */ |
extern pascal void CatchFailures(FailInfo *fi, pascal void (*Handler)(short e, long m, void * |
Handler_StaticLink), void *Handler_StaticLink); |
/* Call this to set up an exception handler. This pushes your handler onto |
a stack of exception handlers. */ |
extern pascal void EachFailureHandlerDo(pascal void (*DoToHandler)(FailInfoPtr fiPtr, void * |
DoToHandler_StaticLink), void *DoToHandler_StaticLink); |
/* Calls DoToHandler for each failure handler in the stack from gTopHandler |
to the outermost handler. */ |
extern pascal void Failure(short error, long message); |
/* Call this to signal a failure. Control will branch to the most recent |
exception handler, which will be popped off the handler stack. */ |
extern pascal void FailMemError(void); |
/* IF MemError <> noErr THEN Failure(MemError, 0); If you are using |
assembler, then you should just test the return code from the Memory |
Manager in DO by calling FailOSErr. (See the discussion of MemError in |
Inside Macintosh.) */ |
extern pascal void FailResError(void); |
/* IF ResError <> noErr THEN Failure(ResError, 0); (See Inside Macintosh.) */ |
extern pascal void FailNewMessage(short error, long oldMessage, long newMessage); |
/* This does: |
IF oldMessage = 0 THEN |
Failure(error, newMessage) |
ELSE |
Failure(error, oldMessage); |
*/ |
extern pascal void FailNIL(void *p); |
/* Call this with a pointer/handle; this signals Failure(memFullErr, 0) if p is NIL. */ |
extern pascal void FailNILResource(void *r); |
/* Call this with a resource handle; this signals Failure if the handle is nil. The error is |
either that returned by ResError, or resNotFound if ResError returns no error. */ |
extern pascal void FailOSErr(short error); |
/* Call this with an OSError; signals Failure(error, 0) if error <> noErr. */ |
extern pascal Boolean HandlerExists(FailInfoPtr testFailInfoPtr); |
/* This test returns TRUE if the failure handler exists in the stack from gTopHandler |
to the outermost handler. */ |
extern pascal void Success(FailInfo *fi); |
/* Call this when you want to pop your exception handler. We assume that the programmer |
passes |
in the most recent FailInfo record; ie. the one that is the top of the stack. If debugging |
is on, we check to be sure. */ |
#endif |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14