If a subroutine performs ``cleaning-up'' operations which must execute even if the inherited status has been set, then a different sequence of status checking must usually be performed. The deferral of error messages may also be involved.
Normally, the effect required is that a cleaning-up routine called with its status argument set to SAI__OK will behave like any other routine, setting the status value and reporting an error if it fails. However, if the value of status has been set to an error condition because of a previous error, it must still attempt to execute, even if there is a good chance that it will not succeed. In this latter case, an error report is not normally required from the cleaning-up routine.
The following is a typical example:
CALL ALLOC( NBYTES, PNTR, STATUS ) <application code> CALL DEALL( NBYTES, PNTR, STATUS )
Here, ALLOC allocates some memory for use by the ``application code'' and DEALL de-allocates it at the end. The following error conditions may arise:
The solution is to write DEALL so that it saves the value of STATUS on entry and restores it again on exit. To preserve the associated error messages, calls to ERR_MARK and ERR_RLSE are also required. For example:
SUBROUTINE DEALL( NBYTES, PNTR, STATUS ) ... * Save the initial status value and set a new value for this routine. ISTAT = STATUS STATUS = SAI__OK * Create a new error context. CALL ERR_MARK <clean-up code> * If the initial status was bad, then ignore all internal errors. IF ( ISTAT .NE. SAI__OK ) THEN CALL ERR_ANNUL( STATUS ) STATUS = ISTAT END IF * Release the current error context. CALL ERR_RLSE END
Note how a new error context is used to constrain ERR_ANNUL to annulling only errors arising from the ``clean-up code'', and not the pre-existing error condition which is to be preserved.
Two routines are provided to ``wrap up'' these clean-up calls: ERR_BEGIN and ERR_END, which begin and end what is effectively a new error reporting environment. ERR_BEGIN will begin a new error context and return the status value set to SAI__OK. A call to ERR_END will annul the current error context if the previous context contains undelivered error messages. It will then release the current error context. ERR_END returns the status of the last reported error message pending delivery to the user after the current error context has been released. If there are no error messages pending output, then the status is returned set to SAI__OK. This behaviour is exactly that represented by the code in the previous example. Here is the previous example re-written using calls to ERR_BEGIN and ERR_END:
SUBROUTINE DEALL( NBYTES, PNTR, STATUS ) ... * Begin a new error reporting environment. CALL ERR_BEGIN( STATUS ) <clean-up code> * End the current error reporting environment. CALL ERR_END( STATUS ) END
Like ERR_MARK and ERR_RLSE, ERR_BEGIN and ERR_END should always occur in pairs and can be nested if required. If ERR_BEGIN is called with STATUS set to an error value, then a check is made to determine if there are any error messages pending output at the current error context; if there are not then the status has been set without making an error report. In these cases ERR_BEGIN will make the error report:
!! Status set with no error report (improper use of EMS).
using the given status value before marking a new error context.
Any code which attempts to execute when the inherited status is set to an error
value should be regarded as ``cleaning-up''.
MERS (MSG and ERR) Message and Error Reporting Systems