home *** CD-ROM | disk | FTP | other *** search
/ AppleScript - The Beta Release / AppleScript - The Beta Release.iso / Documentation / develop / Better Apple Event Coding / Code Samples / UMAFailure.h < prev    next >
Encoding:
Text File  |  1992-10-16  |  8.9 KB  |  211 lines  |  [TEXT/MPS ]

  1. /*[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]*/
  2. /* UFailure.p */
  3. /* Copyright © 1985-1990 by Apple Computer, Inc.  All rights reserved. */
  4.  
  5. /*
  6.                 T H E O R Y  O F     O P E R A T I O N
  7.  
  8.     This unit implements the MacApp failure mechanism.
  9.  
  10.     The failure mechanism is built around exception handlers.    An exception
  11.     handler is a routine, generally local to some other routine, that is
  12.     called when a failure occurs and takes action to handle the failure.
  13.     An exception handler is of the form
  14.  
  15.     PROCEDURE ExceptionHandler (error: OSErr; message: LONGINT);
  16.  
  17.     where error is the error that caused the failure, and message identifies
  18.     the error message that may be displayed.  Consider a routine that opens
  19.     a file, reads its contents, and closes the file.  If a failure occured
  20.     while reading the file, an exception handler would be needed to close the
  21.     file, as the rest of the routine will not be executed.    (See the example
  22.     at the end of these comments.)
  23.  
  24.     References to expection handlers are defined by the FailInfo record.
  25.     The exception handlers form a linked-list via the nextInfo field of
  26.     FailInfo.    The linked list is a stack since new exception handlers
  27.     are added to the front of the list.
  28.  
  29.     New exception handlers are added to the stack with the CatchFailures
  30.     procedure, and removed from the stack with the Success procedure.    In
  31.     general you call CatchFailures to post an exception handler when an
  32.     error the application should handle might occur, and call Success to
  33.     remove the handler from the stack, after the handler is no longer
  34.     needed (i.e. the possibility of error no longer exists).  Any failure
  35.     detected within the limits of the CatchFailures and subsequent Success
  36.     call results in the execution of the exception handler.  (Failure does
  37.     not have to occur in the same routine as your call to CatchFailures.
  38.     The failure may occur in any routine called after CatchFailures but
  39.     before Success.)
  40.  
  41.     When MacApp (or your code) determines that a failure has occured, it
  42.     calls Failure.    As a convenience, several procedures are provided
  43.     to check for standard kinds of failures and call Failure if needed.
  44.     These procedures are:
  45.  
  46.     FailNIL         Calls Failure if its parameter is NIL.
  47.     FailOSErr        Calls Failure if its parameter is not noErr.
  48.     FailMemError    Calls Failure if MemError returns other than noErr.
  49.     FailResError    Calls Failure if ResError returns other than noErr.
  50.  
  51.     When Failure is called, execution of the routine that called Failure is
  52.     terminated and the exception handler at the top of the stack is popped.
  53.     For each routine that was called after the handler was posted
  54.     to the stack, execution is terminated as though from an EXIT statement.
  55.     Then the exception handler is called.    It generally cleans up for the
  56.     routine in which it is nested.    Upon completion the next exception handler
  57.     is popped from the stack, repeating the process.
  58.  
  59.     The error causing the failure, and a message code is passed to Failure.
  60.     For MacApp, the last exception handler on the stack is the one in
  61.     TApplication.PollEvent.  It calls TApplication.ShowError, which calls
  62.     ErrorAlert, which decodes the message and displays an alert.  You exception
  63.     handlers may set the message code to one more specific to your application
  64.     by calling FailNewMessage at the end of your exception handler.
  65.     FailNewMessage changes the message only if the current one is non-zero.
  66.     This has the effect of allowing those exception handlers closest to the
  67.     source of the error to set the message.
  68.  
  69.     One last note about exception handlers:  It is possible for an exception
  70.     handler to terminate exception processing by using a non-local GOTO to
  71.     jump back into the routine in which the exception handler is nested.  This
  72.     is how MacApp keeps the application running when a failure occurs.    The
  73.     last exception handler on the stack, in TApplication.PollEvent, uses a
  74.     GOTO to continue event processing.
  75.  
  76.     The following is an example showing the use of exception handlers.
  77.     The ReadTheFile procedure reads the contents of a file, signalling
  78.     failure if the open, read, or close returns an error.
  79.  
  80.     PROCEDURE ReadTheFile (fileName: Str255; volRefNum: INTEGER;
  81.                             VAR contents: ContentsRecord);
  82.     VAR
  83.         fi:         FailInfo;
  84.         count:        LONGINT;
  85.  
  86.         PROCEDURE ExceptionHandler (error: OSErr; message: LONGINT);
  87.         VAR
  88.             err:    OSErr;
  89.         BEGIN
  90.             err := FSClose(fileRefNum);     { Make sure the file is closed }
  91.             { Pass on my own error message... }
  92.             FailNewMessage(error, message, kMyErrorMessage);
  93.         END;
  94.  
  95.     BEGIN
  96.         { If FSOpen fails we don't need to do any failure handling,
  97.             though the guy that called us probably will. }
  98.         FailOSErr(FSOpen(fileName, volRefNum, fileRefNum));
  99.  
  100.         { Now that the file is open, if the read fails we must make
  101.             sure to close the file. }
  102.         CatchFailures(fi, Exceptionhandler);
  103.  
  104.         count := SIZEOF(ContentsRecord);
  105.         FailOSErr(FSRead(fileRefNum, count, @contents));
  106.  
  107.         { The file's been read so we don't need our exception handler
  108.             anymore. }
  109.         Success(fi);
  110.  
  111.         { Again, the guy that called us will have to deal with this. }
  112.         FailOSErr(FSClose(fileRefNum));
  113.     END;
  114. */
  115.  
  116. #ifndef  __UFailure__
  117. #define __UFailure__  0
  118. #endif
  119. #if  ! __UFailure__
  120. #define __UFailure__  1
  121.  
  122.         /* • Auto-Include the requirements for this unit's interface. */
  123. #ifndef  __TYPES__
  124. #include "Types.h"
  125. #endif
  126.  
  127. const short minErr                = - 32768;                /* Low error number */
  128. const short maxErr                = 32767;                /* High error number */
  129.             /* used for the exception handling mechanism */
  130.             /* Preferred. The pointer type _MUST_ be declared first
  131.                since the record is self referential */
  132. typedef struct FailInfo *FailInfoPtr;
  133. struct FailInfo {
  134.     long regs[11];                            /* The saved registers as of the
  135.                                                CatchFailures. */
  136.     short error;                            /* The error condition passed to Failure. */
  137.     long message;                            /* The message which accompanied the Failure. */
  138.     long failA6;                            /* A6 of the caller to CatchFailures. */
  139.     long failPC;                            /* Address of failure handler routine. */
  140.     FailInfoPtr nextInfo;                    /* Next in stack. */
  141. };
  142. typedef FailInfoPtr PFailInfo;                            /* Left in for compatibility (2.0) */
  143.  
  144. extern pascal FailInfoPtr gTopHandler;
  145.    /* Most recent link in linked list of failure
  146.       handlers. Set to nil by a constant in
  147.       UFailure.a so that Failure handling never
  148.       needs to be initialized. */
  149.  
  150. extern pascal void Assertion(Boolean condition, StringPtr description);
  151.         /* Asserts a condition.If condition is FALSE : IF debugging : prints description and
  152.            stops in Debugger ELSE : Signals a general failure. */
  153.  
  154. pascal long BuildMessage(short lowWord, short highWord)
  155.     =  0x2E9F;                                            /* MOVE.L (A7)+,(A7) */
  156.         /* Takes the 2 integers and combines them into a LONGINT failure message.  Note that the
  157.         low-order word is the first parameter. */
  158.  
  159. extern pascal void CatchFailures(FailInfo *fi, pascal void (*Handler)(short e, long m, void *
  160.    Handler_StaticLink), void *Handler_StaticLink);
  161.         /* Call this to set up an exception handler. This pushes your handler onto
  162.         a stack of exception handlers. */
  163.  
  164. extern pascal void EachFailureHandlerDo(pascal void (*DoToHandler)(FailInfoPtr fiPtr, void *
  165.    DoToHandler_StaticLink), void *DoToHandler_StaticLink);
  166.         /* Calls DoToHandler for each failure handler in the stack from gTopHandler
  167.         to the outermost handler. */
  168.  
  169. extern pascal void Failure(short error, long message);
  170.         /* Call this to signal a failure.  Control will branch to the most recent
  171.         exception handler, which will be popped off the handler stack. */
  172.  
  173. extern pascal void FailMemError(void);
  174.         /* IF MemError <> noErr THEN Failure(MemError, 0); If you are using
  175.         assembler, then you should just test the return code from the Memory
  176.         Manager in DO by calling FailOSErr. (See the discussion of MemError in
  177.         Inside Macintosh.) */
  178.  
  179. extern pascal void FailResError(void);
  180.         /* IF ResError <> noErr THEN Failure(ResError, 0); (See Inside Macintosh.) */
  181.  
  182. extern pascal void FailNewMessage(short error, long oldMessage, long newMessage);
  183.         /* This does:
  184.         IF oldMessage = 0 THEN
  185.             Failure(error, newMessage)
  186.         ELSE
  187.             Failure(error, oldMessage);
  188.         */
  189.  
  190. extern pascal void FailNIL(void *p);
  191.         /* Call this with a pointer/handle; this signals Failure(memFullErr, 0) if p is NIL. */
  192.  
  193. extern pascal void FailNILResource(void *r);
  194.         /* Call this with a resource handle; this signals Failure if the handle is nil. The error is
  195.         either that returned by ResError, or resNotFound if ResError returns no error. */
  196.  
  197. extern pascal void FailOSErr(short error);
  198.         /* Call this with an OSError; signals Failure(error, 0) if error <> noErr. */
  199.  
  200. extern pascal Boolean HandlerExists(FailInfoPtr testFailInfoPtr);
  201.         /* This test returns TRUE if the failure handler exists in the stack from gTopHandler
  202.         to the outermost handler.  */
  203.  
  204. extern pascal void Success(FailInfo *fi);
  205.         /* Call this when you want to pop your exception handler. We assume that the programmer
  206.            passes
  207.         in the most recent FailInfo record; ie. the one that is the top of the stack. If debugging
  208.         is on, we check to be sure. */
  209. #endif
  210.  
  211.