If both $ETRAP and $ZTRAP are set to the empty string upon encountering an error, the current level is discarded and the error is reissued at the invoking level. When already at the lowest M stack level, GT.M terminates routine execution and returns control to the DCL level. If $ZTRAP is used exclusively, $ZTRAP="" suppresses the unstacking of NEWed values of $ZTRAP associated with lower levels. $ETRAP values are always unstacked, however if the lowest level $ETRAP is the empty string (which it is by default when GT.M starts), GT.M performs the same termination as it does with $ZTRAP. These terminations with both ISVs empty provides a mechanism for returning to DCL with a status message when GT.M encounters an error.
Example:
GTM>ZPRINT ^EP7
EP7WRITE !,"THIS IS ",$TEXT(+0)
SET $ECODE="";this only affects $ETRAP
SET $ETRAP="",$ZTRAP=""
KILL A
BADWRITE A
WRITE !,"THIS IS NOT DISPLAYED"
QUIT
GTM>DO ^EP7
THIS IS EP7
%GTM-E-UNDEF, Undefined local variable: A
%GTM_I-RTSLOC,At M source location BAD^EP7
$ WRITE SYS$OUTPUT $STATUS
%X08F685DA
GT.M issues a message describing the M error and releases control to the invoking DCL. If your application packages M invocations in DCL, the DCL can determine the nature of the exit by examining the VMS symbol $STATUS.
When the action specified by $ZTRAP results in another run-time error before changing the value of $ZTRAP, the routine may iteratively invoke $ZTRAP until a stack overflow terminates the GT.M image. SETting $ZTRAP="" at the beginning of error processing ensures that this type of infinite loop does not occur. Because $ETRAP is implicitly followed by a QUIT it does not have the tendency to recurse. While $ETRAP is resistant to recursion, it is not completely immune, because a GOTO or a ZGOTO within the same level can evade the implicit QUIT. $ETRAP error handling involving errors on more than one stack level can also be induced to recurse if $ECODE is inappropriately cleared before the errors at all levels have been properly dealt with.
Example:
GTM>ZPRINT ^EP8 EP8WRITE !,"THIS IS ",$TEXT(+0) NEW $ZTRAP SET $ZTRAP="DO ET" KILL A BADWRITE A WRITE !,"THIS IS NOT DISPLAYED" QUIT ETWRITE 2/0 QUIT GTM>DO ^EP8 THIS IS EP8 %GTM-E-STACKCRIT, Stack space critical %GTM-E-ERRWZTRAP, Error while processing $ZTRAP $
When the routine encounters an error at label BAD, GT.M transfers control to label ET. When the routine encounters an error at label ET, it recursively does ET until a stack overflow condition terminates the GT.M image.
A set $ZTRAP="" command as soon as the program enters an error-handling routine prevents this type of "infinite" recursion.
GTM>ZPRINT ^EP8A
EP8AWRITE !,"THIS IS ",$TEXT(+0)
SET $ECODE=""
SET $ZTRAP="",$ETRAP="DO ET"
KILL A
BADWRITE A
WRITE !,"THIS IS NOT DISPLAYED"
QUIT
ETWRITE !,"CONTINUING WITH ERROR TRAP AFTER AN ERROR"
ZSHOW "S"
WRITE !,"HERE COMES AN ERROR IN THE TRAP CODE"
WRITE 2/0
QUIT
GTM>DO ^EP8A
THIS IS EP8A
CONTINUING WITH ERROR TRAP AFTER AN ERROR ET+1^EP8A
Indirection ($ZTRAP)
+1^GTM$DMOD (Direct mode)
HERE COMES AN ERROR IN THE TRAP CODE
GTM>
This demonstrates how $ETRAP behavior in this circumstance is more appropriate. Note that the $ZTRAP="" at the lowest level, prevents exection from returning to Direct Mode when the initial value of $ZTRAP ("B") is unstacked; this step takes $ZTRAP out of the equation and should be part of initialization when the intention is to use $ETRAP exclusively.
Example:
GTM>ZPRINT ^EP9
EP9WRITE !,"THIS IS ",$TEXT(+0)
SET $ZTRAP="DO ET"
KILL A
BADWRITE A
WRITE !,"THIS IS NOT DISPLAYED"
QUIT
ETSET $ZT=""
WRITE !,"THIS IS THE ERROR TRAP"
ERRORWRITE !,"HERE COMES AN ERROR IN THE ERROR TRAP"
WRITE 2/0
QUIT
GTM>DO ^EP9
THIS IS EP9
THIS IS THE ERROR TRAP
HERE COMES AN ERROR IN THE ERROR TRAP
%GTM-E-LABELMISSING, Label referenced but not defined: ET
%GTM_E-ERRWETRAP, Error while processing $ETRAP
%GTM-E-DIVZERO, Attempt to divide by zero
$
This routine sets the value of $ZTRAP to null as soon as the program enters the error handler. This insures program termination when an error occurs in the error handler.