3.5 TCL ERRORS AND EXCEPTION HANDLING

For handling of errors in procedures and for determining the completion status of a command, TCL provides the variables _ONFAIL, $SFI, and $SKEY.

3.5.1 _ONFAIL Exception Handling

The variable _ONFAIL is an implicitly defined local string variable that dictates the behavior of the procedure when a command fails or a user aborts the procedure. The variable _ONFAIL may have one or two components; the initial count for _ONFAIL is one. The value of _ONFAIL(1) is a TCL command string that is to be executed when a command in the procedure fails. (Command success or failure is determined by the value of the global $SFI; see below.) The value of _ONFAIL(2) is a TCL command string that is executed when a user aborts the procedure from the proc interrupt mode.

The legal values for both components of ONFAIL are "GOTO label", "BREAK", "NEXT", "CONTINUE", "STOP", and "RETURN".

The rules relating to _ONFAIL(1) are:

  1. When a procedure is initiated, the _ONFAIL(1) variable for the procedure is automatically set to "RETURN"; thus, the default error handling is to terminate the proc, passing on lower level errors to the invoking proc.

  2. The _ONFAIL(1) command is used upon the failure of any proc, any command listed in the "TAE Command Language (TCL) User's Manual," and some of the commands listed in Section 3.4.2 of this manual. Failure of a command is indicated by a negative $SFI upon command completion. (The "Usage Notes" section of the command description indicates when an _ONFAIL(1) is used.)

  3. If a command fails, and it is one of the commands for which _ONFAIL(1) is ignored (e.g., a bad IF command), TAE forces a RETURN (thus aborting the containing proc), and sets $SFI to -1.

  4. If the command in _ONFAIL(1) is executed, and the command is invalid, then $SFI is set negative and a proc RETURN is forced.

The rules relating to _ONFAIL(2) are:

  1. Care must be used with _ONFAIL(2). If the ONFAIL(2) command causes an infinite loop in a procedure, then the user can never abort the procedure.

  2. If ONFAIL(2) does not exist at the point of the ABORT command, the current procedure is terminated and the abort condition is passed to the invoking procedure.

    TAE continues to terminate procedure levels until a procedure is found with a value for ONFAIL(2). If no procedure level indicates such a willingness to handle the abort condition, control returns to the interactive level, with all procedure levels terminated.

  3. If the command in _ONFAIL(2) is executed, and the command is invalid, then SSFI is set negative and a proc RETURN is forced.

3.5.2 $SFI Success Indication and $SKEY Status

Proc success is determined by the setting of the global integer $SFI, the "success/fail indicator." A negative value implies failure, a positive value success. $SFI is implicitly set to a positive value upon proc activation so that a proc that does not explicitly change $SFI terminates with a "success" status.

$SKEY is a global string that, by convention, contains descriptive status information from the last command executed. $SKEY is implicitly set to the empty string upon proc and command activation.

Both processes and procedures may set $SFI and $SKEY: A procedure sets these globals using LET, PUTMSG, or RETURN; a process sets the values upon exit (using XZEXIT in Section 3.5 of the "TAE Command Language (TCL) Runtime Services, Volume 2: FORTRAN", z_exit in Section 8 of the "TAE Command Language (TCL) Runtime Services, Volume 1: C" or z_exit in Appendix C of the "TAE Plus Ada Reference Manual"). By default, the LOGOFF and EXIT TCL commands return the current value of $SFI to the host operating system as job completion status. The LOGOFF and EXIT commands also have a parameter named $SFI to set the completion status explicitly.

For batch and async jobs, TAE generates TCL code so that the completion status of the job is the completion status of the particular proc that was run.

3.5.3 Error Handling Examples

  1. LET _ONFAIL = "GOTO ERROR"

    Proc invocations subsequent to this LET command direct control to the line labelled ERROR if $SFI indicates an error status. Note that the line labelled ERROR must imply a forward branch at the point of the failure.

  2. LET ONFAIL = "CONTINUE"
    IMGCQPY FROM=11 TO=12
    IF ($SFI < 0)      !if an error detected...
        .
        .
        .
    

    In this example, the error handling command is set to "CONTINUE" so that the procedure can handle errors in-line.

  3. LET _ONFAIL(2) = "GOTO CLEANUP"

    If a user aborts this procedure, the control will go to the line labelled CLEANUP.

  4. LET _ONFAIL(2) "CONTINUE"

    This procedure cannot be aborted.

3.5.4 Suppressing Messages in TCL

A TCL procedure may suppress the display of error messages by declaring a local string variable named _MESSAGE. If the _MESSAGE variable exists at the point that the TCL interpreter would normally display an error message, TAE places the message string in the _MESSAGE variable rather than displaying the string. This feature allows a TCL procedure to handle expected errors without confusing the user.

The following example is a TCL procedure that erases a WPT panel; if the panel does not exist, no error message is displayed:

procedure
    parm panelNam              ! name of panel to erase
body
    let _onfail = "continue"   ! continue on wpt-erase error
    local _message             ! suppress error message
    wpt-erase @panelNam        ! delete panel
    return $sfi=1 $skey=""     ! normal return
end-proc

The following code segment shows how message suppression may be turned on and off by deleting and re-declaring the _MESSAGE variable:

local _message           ! suppress error messages
...
delete _message          ! back to normal message
...
local _message           ! mode suppress error messages

The following example shows a TCL procedure that maintains values of its local variables from invocation to invocation. The locals are maintained in a PAR file that has the same file name as the PDF. When the proc is run for the first time, there is no complaint that the PAR file does not exist:

procedure
    local (a, b) integer initial=0
body
    let _onfail = "continue"
    local _message	     ! don't complain if error in ...
    restore-locals @proc     ! restore local variables
    delete _message          ! enable message output
    let a = a + 1            ! update "static" locals
    let b = b + 1
    display (a, b)           ! show +1. on every invocation
    save-locals @_proc       ! save local variables
end-proc