next up previous 211
Next: Error table limits
Up: ERR - Error Reporting System
Previous: Adding contextual information


Deferred error reporting

The action of the subroutine ERR_REP is to report an error to the Error System but the Error System has the capacity to defer the output of that message to the user. This allows the final delivery of error messages to be controlled within applications software, and this control is achieved using the subroutines ERR_MARK, ERR_RLSE, ERR_FLUSH and ERR_ANNUL. This section describes the function of these subroutines and how they are used.

Subroutine ERR_MARK has the effect of ensuring that all subsequent error messages are deferred by the Error System and stored in an ``error table'' instead of being delivered immediately to the user. ERR_MARK also starts a new ``error context'' which has its own table of error messages and message tokens which are independent of those in the previous error context. A return to the previous context can later be made by calling ERR_RLSE. When ERR_RLSE is called, the new error context created by ERR_MARK ceases to exist and any error messages stored in it are transferred to the previous context. Calls to ERR_MARK and ERR_RLSE can be nested if required but should always occur in matching pairs. In this way, no existing error messages can be lost through the deferral mechanism.

The system starts at base-level context (level 1) - at this level, error messages are output to the user immediately. If a call to ERR_RLSE returns the system to base-level context, any messages still stored in the error table will be automatically delivered to the user.

The purpose of deferred error reporting can be illustrated by the following example. Consider a subroutine, say HELPER, which detects an error during execution. The subroutine HELPER reports the error that has occurred, giving as much contextual information about the error as it can. It also returns an error status value, enabling the software that called it to react to the failure appropriately. However, what may be considered an ``error'' at the level of subroutine HELPER, e.g. an ``end of file'' condition, may be considered by the calling module to be a case which can be handled without informing the user, e.g. by simply terminating its input sequence. Thus, although the subroutine HELPER will always report the error condition, it is not always necessary for the associated error message to reach the user. The deferral of error reporting enables application programs to handle such error conditions internally.

Here is a schematic example of what subroutine HELPER might look like:

      SUBROUTINE HELPER( LINE, STATUS )

      ...

*  Check if a Fortran I/O error has occurred.
      IF ( IOSTAT .NE. 0 ) THEN

*     Set STATUS and report the error.
         IF ( IOSTAT .LT. 0 ) THEN

*        Report an end-of-file error.
            STATUS = <end-of-file error code>
            CALL ERR_REP( 'HELPER_FIOER', 
     :         'Fortran I/O error: end of input file reached', STATUS )
         ELSE

*        Report a Fortran I/O error.
            STATUS = SAI__ERROR
            CALL ERR_REP( 'HELPER_FIOER', 
     :         'Fortran I/O error encountered during data input',
     :         STATUS )
         END IF

*     Abort.
         GO TO 999
      END IF

      ...

 999  CONTINUE
      END

Suppose HELPER is called and reports an error, returning with STATUS set. At this point, the error message may, or may not, have been received by the user - this will depend on the environment in which the routine is running, and on whether the software which called HELPER took any action to defer the error report. HELPER itself does not need to take action (indeed it should not take action) to ensure delivery of the message to the user; its responsibility ends when it aborts, and responsibility for handling the error condition then passes to the software which called it.

Now suppose that the subroutine HELPED calls HELPER and wishes to defer any messages from HELPER so that it can decide how to handle error conditions itself, rather than troubling the user with spurious messages. It can do this by calling the routine ERR_MARK before it calls HELPER.

The operation of error message deferral can be illustrated by a simple example:

      SUBROUTINE HELPED( STATUS )

      ...

*  Create a new error context.
      CALL ERR_MARK

      <any error messages from HELPER are now deferred>

      CALL HELPER( LINE, STATUS )

      ...

By calling ERR_MARK before calling HELPER, subroutine HELPED ensures that any error messages reported by HELPER are deferred, i.e. held in the error table. HELPED can then handle the error condition itself in one of two ways:

Here is the previous example, elaborated to demonstrate the use of ERR_ANNUL. It shows how an ``end of file'' condition from HELPER might be detected, annulled, and stored by HELPED in a logical variable EOF for later use:

*  Initialise end-of-file flag, EOF.
      EOF = .FALSE.

*  Create a new error context.
      CALL ERR_MARK

*  Read line of data.
      CALL HELPER( LINE, STATUS )

*  Trap end-of-file error status and annul any reported error messages
*  for the current error context.
      IF ( STATUS .EQ. <end-of-file error status> ) THEN
         CALL ERR_ANNUL( STATUS )
         EOF = .TRUE.
      END IF

*  Release the current error context.
      CALL ERR_RLSE

*  Abort application on error.
      IF ( STATUS .NE. SAI__OK ) GO TO 999

      ...

999   CONTINUE
      END

Note that the routine chooses only to handle ``end of file'' error conditions; any other error condition will not be annulled and will subsequently cause an abort when STATUS is checked after the call to ERR_RLSE.

Here is an example showing how both ERR_FLUSH and ERR_ANNUL may be used during the process of acquiring a value from the user via a call to the subroutine RDPAR:

*  Create a new error context.
      CALL ERR_MARK

*  Loop to get DSCALE parameter value.
      DO WHILE ( .TRUE. )
         CALL RDPAR( 'DSCALE', DSCALE, STATUS )

*     Check the returned global status.
         IF ( STATUS .EQ. SAI__OK ) THEN

*        Success, so continue with the application.
            GO TO 10
         ELSE IF ( STATUS .EQ. <abort status> ) THEN

*        User wanted to abort, so abort the application.
            CALL ERR_RLSE
            GO TO 999
         ELSE IF ( STATUS .EQ. <null status> ) THEN

*        User entered "null", so annul the error and supply a default.
            CALL ERR_ANNUL( STATUS )
            DSCALE = 1.0
            GO TO 10
         ELSE

*        An error has occurred, so ensure the user knows about it before
*        trying again.
            CALL ERR_FLUSH( STATUS )
            CALL CNPAR( 'DSCALE', STATUS )
         END IF
      END DO

 10   CONTINUE

*  Release the current error context.
      CALL ERR_RLSE

      ...

 999  CONTINUE
      END

Note how ERR_FLUSH is used to ensure that any error messages are output to the user before trying again to get a new value. In effect, it passes responsibility for the error condition to the user. This interactive situation is typical of how ERR_FLUSH should be used; it is not needed very often during normal error reporting, and it is certainly not required as a regular means of ensuring the delivery of error messages following calls to ERR_REP - this should be left to the Error System itself when returned to the base-level context.

Note that if ERR_FLUSH cannot output the error message to the user, then it will return the error status ERR__OPTER. This allows critical applications to attempt to recover in the event of the failure of the Error System.

Finally, as a safety feature, if ERR_FLUSH is called when no errors have been reported, it outputs the message

!! No error to report (improper use of EMS).

This is to highlight problems where the inherited status has been set by some item of software, but no accompanying error message has been reported.



next up previous 211
Next: Error table limits
Up: ERR - Error Reporting System
Previous: Adding contextual information

MERS (MSG and ERR) Message and Error Reporting Systems
Starlink User Note 104
P C T Rees
A J Chipperfield
22 October 2001
E-mail:ussc@star.rl.ac.uk

Copyright © 2001 Council for the Central Laboratory of the Research Councils