In the following examples (and the previous one as well), $ETRAP and $ZTRAP in most cases have similar behavior. The most prominent difference is that, when $ETRAP is active, $ECODE determines whether or not a second error in an M stack level triggers an immediate implicit QUIT from that level. For additional information, see the sections on $ECODE and $ETRAP in Chapter 8: “Intrinsic Special Variables”. Because of the effect of $ECODE on the processing flow when $ETRAP is active, there is a benefit to including appropriate $ECODE maintenance in $ZTRAP related code, so that things stay well behaved when the two mechanisms are intemixed. Other differences are discussed in some of the examples.
When $ZTRAP is set to a BREAK command and an error occurs, GT.M puts the process into Direct Mode. The default for $ZTRAP is a BREAK command. When developing a program, $ZTRAP="BREAK" allows you to investigate the cause of the error from Direct Mode. For information on GT.M debugging tools, see Chapter 4: “Operating and Debugging in Direct Mode”.
Example:
GTM>zprint ^EP1 EP1 WRITE !,"THIS IS "_$TEXT(+0) KILL A BAD WRITE A WRITE !,"THIS IS NOT DISPLAYED" QUIT GTM>do ^EP1 THIS IS EP1%GTM-E-UNDEF, Undefined local variable: A At M source location BAD^EP1 GTM>ZSHOW BAD^EP1 ($ZTRAP) (Direct mode) +1^GTM$DMOD (Direct mode) GTM>QUIT GTM>ZSHOW EP1+1^EP1 (Direct mode) +1^GTM$DMOD (Direct mode) GTM>
Because by default $ETRAP="" and $ZTRAP="B", this example does not explicitly set either $ETRAP or $ZTRAP. When the routine encounters an error at BAD^EP1, GT.M initiates Direct Mode. The ZSHOW displays the M stack that has, at the bottom, the base Direct Mode frame and, at the top, EP1 with a notation that $ZTRAP has been invoked. The QUIT command at the prompt removes EP1 from the stack.
To prevent a program such as a production image from accessing Direct Mode, assign an action other than "BREAK" to $ETRAP or $ZTRAP. The following sections discuss various alternative values for $ETRAP or $ZTRAP.
In order to prevent inappropriate access to Direct Mode, eliminate all BREAKs from the production code. If the code contains BREAK commands, the commands should be subject to a postconditional flag that is only turned on for debugging. ZBREAK serves as an alternative debugging tool that effects only the current process and lasts only for the duration of an image activation.
The GOTO command instructs GT.M to transfer execution permanently to another line within the routine or to another routine. When stopping to investigate an error is undesirable, use the GOTO command in $ETRAP or $ZTRAP to continue execution at some other point.
Example:
GTM>ZPRINT ^EP2 EP2 WRITE !,"THIS IS "_$TEXT(+0) SET $ECODE="" ;this affects only $ETRAP SET $ETRAP="GOTO ET" ;this implicitly stacks $ZTRAP ;N $ZT S $ZT="GOTO ET" ;would give a similar result DO SUB1 WRITE !,"THIS IS THE END" QUIT SUB1 WRITE !,"THIS IS SUB1" DO SUB2 QUIT SUB2 WRITE !,"THIS IS SUB2" KILL A BAD WRITE A WRITE !,"THIS IS NOT DISPLAYED" QUIT ET ;SET $ZTRAP="" ;if using $ZTRAP to prevent recursion WRITE !,"CONTINUING WITH ERROR TRAP AFTER AN ERROR" WRITE !,"$STACK: ",$STACK WRITE !,"$STACK(-1): ",$STACK(-1) WRITE !,"$ZLEVEL: ",$ZLEVEL FOR I=$STACK(-1):-1:1 DO . WRITE !,"LEVEL: ",I . SET K=10 . FOR J="PLACE","MCODE","ECODE" DO . . WRITE ?K," ",J,": ",$STACK(I,J) . . SET K=K+20 WRITE !,$ZSTATUS,! ZSHOW "S" SET $ECODE="" ;this affects only $ETRAP QUIT GTM>do ^EP2 THIS IS EP2 THIS IS SUB1 THIS IS SUB2 CONTINUING WITH ERROR TRAP AFTER AN ERROR $STACK: 3 $STACK(-1): 3 $ZLEVEL: 4 LEVEL: 3 PLACE: BAD^EP2 MCODE: BAD WRITE A ECODE: ,M6,Z150373850, LEVEL: 2 PLACE: SUB1+1^EP2 MCODE: DO SUB2 ECODE: LEVEL: 1 PLACE: EP2+4^EP2 MCODE: DO SUB1 ECODE: 150373850,BAD^EP2,%GTM-E-UNDEF, Undefined local variable: A ET+12^EP2 SUB1+1^EP2 EP2+4^EP2 +1^GTM$DMOD (Direct mode) THIS IS THE END GTM>
This routine specifies a GOTO command transferring execution to the ET label when an error occurs. The $ZLEVEL special variable contains an integer indicating the M stack level.
The ZGOTO command is similar to the GOTO command, however, the ZGOTO allows the removal of multiple levels from the program stack. ZGOTO can ensure that execution returns to a specific point, such as a menu.
Example:
GTM>ZPRINT ^EP3 EP3 ; MENU WRITE !,"THIS IS MENU IN ",$TEXT(0) SET $ECODE="" ;this affects only $ETRAP SET $ETRAP="SET $ECODE="""" ZGOTO 2" ;N $ZT S $ZT="ZGOTO 2" ;would give a similar result DO SUB1 WRITE !,"`MENU' AFTER $ETRAP" WRITE !,"$STACK: ",$STACK WRITE !,"$ZLEVEL: ",$ZLEVEL QUIT SUB1 WRITE !,"THIS IS SUB1" DO SUB2 WRITE !,"THIS IS SKIPPED BY ZGOTO" QUIT SUB2 WRITE !,"THIS IS SUB2" KILL A BAD WRITE A WRITE !,"THIS IS NOT DISPLAYED" QUIT GTM>do ^EP3 THIS IS MENU IN THIS IS SUB1 THIS IS SUB2 `MENU' AFTER $ETRAP $STACK: 1 $ZLEVEL: 2
This routine instructs GT.M to reset the execution to level 2 if it encounters an error. GT.M removes all intermediate levels.
In general, coding ZGOTO level information based on $ZLEVEL provides a more robust technique than the "hard-coding" shown in the previous example.
Example:
GTM>ZPRINT ^EP4 EP4 WRITE !,"THIS IS "_$TEXT(+0) SET $ECODE="" ;this affects only $ETRAP DO MAIN WRITE !,"THIS IS ",$TEXT(+0)," AFTER THE ERROR" WRITE !,"$ZLEVEL: ",$ZLEVEL QUIT MAIN WRITE !,"THIS IS MAIN" WRITE !,"$ZLEVEL: ",$ZLEVEL SET $ETRAP="ZGOTO "_$ZLEVEL_":ET" ;N $ZT S $ZT="ZGOTO "_$ZLEVEL_":ET ;alternative DO SUB1 QUIT SUB1 WRITE !,"THIS IS SUB1" WRITE !,"$ZLEVEL: ",$ZLEVEL DO SUB2 QUIT SUB2 WRITE !,"THIS IS SUB2" WRITE !,"$ZLEVEL :",$ZLEVEL KILL A BAD WRITE A WRITE !,"THIS IS NOT DISPLAYED" QUIT ET ;SET $ZTRAP="" ;if using $ZTRAP to prevent recursion WRITE !,"CONTINUING WITH ERROR TRAP AFTER AN ERROR" WRITE !,"$STACK: ",$STACK WRITE !,"$STACK(-1): ",$STACK(-1) WRITE !,"$ZLEVEL: ",$ZLEVEL FOR I=$STACK(-1):-1:1 DO . WRITE !,"LEVEL: ",I . SET K=10 . FOR J="PLACE","MCODE","ECODE" DO . . WRITE ?K," ",J,": ",$STACK(I,J) . . SET K=K+20 WRITE !,$ZSTATUS,! ZSHOW "S" SET $ECODE="" ;this affects only $ETRAP QUIT GTM>do ^EP4 THIS IS EP4 THIS IS MAIN $ZLEVEL: 3 THIS IS SUB1 $ZLEVEL: 4 THIS IS SUB2 $ZLEVEL :5 CONTINUING WITH ERROR TRAP AFTER AN ERROR $STACK: 2 $STACK(-1): 4 $ZLEVEL: 3 LEVEL: 4 PLACE: BAD^EP4 MCODE: BAD WRITE A ECODE: ,M6,Z150373850, LEVEL: 3 PLACE: SUB1+2^EP4 MCODE: DO SUB2 ECODE: LEVEL: 2 PLACE: MAIN+4^EP4 MCODE: DO SUB1 ECODE: LEVEL: 1 PLACE: EP4+2^EP4 MCODE: DO MAIN ECODE: 150373850,BAD^EP4,%GTM-E-UNDEF, Undefined local variable: A ET+12^EP4 EP4+2^EP4 +1^GTM$DMOD (Direct mode) THIS IS EP4 AFTER THE ERROR $ZLEVEL: 2 GTM>
This routine sets $ETRAP or $ZTRAP to a ZGOTO specifying the current level. When the routine encounters an error at label BAD, GT.M switches control to label ET at the level where $ETRAP (or $ZTRAP) was established. At this point in the execution, ET replaces SUB1+2^EP4 as the program stack entry for the level specified, that is, $ZLEVEL=3. The QUIT command then returns control to the level where $ZLEVEL=2.
The command NEW $ETRAP or NEW $ZTRAP stacks the current value of $ETRAP or $ZTRAP respectively and, in the case of $ZTRAP, sets the value equal to the empty string. Normally, a SET $ETRAP or $ZTRAP immediately follows a NEW $ETRAP or $ZTRAP. When GT.M encounters a QUIT command that leaves a level where $ETRAP or $ZTRAP had been NEWed, GT.M deletes any value set to the ISV after the NEW command and restores the value that the ISV held previous to the NEW. NEW $ETRAP or $ZTRAP enables the construction of error handlers corresponding to the nesting of routines. A SET $ETRAP or $ZTRAP implicitly NEWs the other variable if it does not already have the value of the empty string. This enables the interleaving of $ETRAP and $ZTRAP at different levels, although (as mentioned above) such interleaving requires that $ZTRAP handlers deal appropriately with $ECODE.
Example:
GTM>ZPRINT ^EP5 EP5 WRITE !,"THIS IS "_$TEXT(+0) SET $ECODE="";this affects only $ETRAP WRITE !,"STARTING $ETRAP: ",$ETRAP WRITE !,"STARTING $ZTRAP: ",$ZTRAP DO SUB1 WRITE !,"ENDING $ETRAP: ",$ETRAP WRITE !,"ENDING $ZTRAP: ",$ZTRAP QUIT MAIN WRITE !,"THIS IS MAIN" WRITE !,"$ZLEVEL: ",$ZLEVEL DO SUB1 QUIT SUB1 WRITE !,"THIS IS SUB1" NEW $ETRAP SET $ETRAP="GOTO ET1" ;NEW $ZTRAP SET $ZTRAP="GOTO ET1" ;alternative WRITE !,"$ETRAP FOR SUB1: ",$ETRAP KILL A BAD WRITE A WRITE !,"THIS IS NOT DISPLAYED" QUIT ET1 WRITE !,"ERROR TRAP 1" WRITE !,"$ETRAP AFTER THE TRAP: ",$ETRAP WRITE !,"$ZTRAP AFTER THE TRAP: ",$ZTRAP SET $ECODE="";this affects only $ETRAP QUIT GTM>do ^EP5 THIS IS EP5 STARTING $ETRAP: STARTING $ZTRAP: B THIS IS SUB1 $ETRAP FOR SUB1: GOTO ET1 ERROR TRAP 1 $ETRAP AFTER THE TRAP: GOTO ET1 $ZTRAP AFTER THE TRAP: ENDING $ETRAP: ENDING $ZTRAP: B GTM>
At SUB1, this routine NEWs $ETRAP and assigns it a value, which implicitly NEWs $ZTRAP. When the routine encounters an error at the SUB1 level, GT.M transfers control to label ET1 without modifying the value of $ETRAP or $ZTRAP. When the routine encounters a QUIT command in routine ET1, GT.M transfers control to the command after the DO that invoked ET1 and restores $ETRAP or $ZTRAP to the values they held before the NEW and the SET.
Note | |
---|---|
If the transfer to ET1 was accomplished with a ZGOTO that reduced the stack level, after the trap, $ETRAP would have the value of the empty string and $ZTRAP would be "B". |
$ETRAP or $ZTRAP set to a DO command instructs GT.M to transfer execution temporarily to another line within this or another routine when it encounters an error. A QUIT command within the scope of the DO transfers control back to the code specified by the $ETRAP or $ZTRAP. When the code in the ISV terminates due to an explicit or implicit QUIT, the behavior of $ETRAP and $ZTRAP is different. When $ETRAP is in control, the level at which the error occurred is removed, and control returns to the invoking level. When $ZTRAP contains code, execution picks up at the beginning of the line with the error. A DO command within $ZTRAP is normally used for I/O errors that an operator may resolve, because a DO command permits re-execution of the line containing the error.
Example:
GTM>ZPRINT ^EP6 EP6 WRITE !,"THIS IS "_$TEXT(+0) NEW NEW $ZTRAP SET $ZTRAP="DO ET" SET (CB,CE)=0 BAD SET CB=CB+1 WRITE A SET CE=CE+1 WRITE !,"AFTER SUCCESSFUL EXECUTION OF BAD:",! SET A="A IS NOT DEFINED" ZWRITE QUIT ET W !,"CONTINUING WITH ERROR TRAP AFTER AN ERROR",! ZWRITE SET A="A IS NOW DEFINED" GTM>do ^EP6 THIS IS EP6 CONTINUING WITH ERROR TRAP AFTER AN ERROR CB=1 CE=0 A IS NOW DEFINED AFTER SUCCESSFUL EXECUTION OF BAD: A="A IS NOT DEFINED" CB=2 CE=1 GTM>
This example sets $ZTRAP to a DO command. When the routine encounters an error in the middle of the line at label BAD, GT.M transfers control to label ET. After QUITting from routine ET, GT.M returns control to the beginning of the line at label BAD.
Example:
GTM>ZPRINT ^EP6A EP6A WRITE !,"THIS IS "_$TEXT(+0) NEW NEW $ETRAP SET $ETRAP="GOTO ET" SET (CB,CE)=0 BAD SET CB=CB+1 WRITE A SET CE=CE+1 WRITE !,"AFTER SUCCESSFUL EXECUTION OF BAD:",! ZWRITE QUIT ET W !,"CONTINUING WITH ERROR TRAP AFTER AN ERROR",! ZWRITE SET A="A IS NOW DEFINED" SET RETRY=$STACK($STACK,"PLACE") SET $ECODE="" GOTO @RETRY GTM>DO ^EP6A THIS IS EP6A CONTINUING WITH ERROR TRAP AFTER AN ERROR CB=1 CE=0 A IS NOW DEFINED AFTER SUCCESSFUL EXECUTION OF BAD: A="A IS NOW DEFINED" CB=2 CE=1 RETRY="BAD^EP6A" GTM>
This routine is an example of how $ETRAP handling can be coded to perform the same kind of resumtion of the original execution stream that occurs by default with $ZTRAP when there is no unconditional transfer of control.
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 shell 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 the shell with a status message when GT.M encounters an error.
Example:
GTM>ZPRINT ^EP7 EP7 WRITE !,"THIS IS ",$TEXT(+0) SET $ECODE="";this only affects $ETRAP SET $ETRAP="",$ZTRAP="" KILL A BAD WRITE 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 $
GT.M issues a message describing the M error and releases control to the shell.
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 EP8 WRITE !,"THIS IS ",$TEXT(+0) NEW $ZTRAP SET $ZTRAP="DO ET" KILL A BAD WRITE A WRITE !,"THIS IS NOT DISPLAYED" QUIT ET WRITE 2/0 QUIT GTM>DO ^EP8 THIS IS EP8 %GTM-E-STACKCRIT, Stack space critical %GTM-E-ERRWZTRAP, Error while processing $ZTRAP GTM>
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 EP8A WRITE !,"THIS IS ",$TEXT(+0) SET $ECODE="" SET $ZTRAP="",$ETRAP="DO ET" KILL A BAD WRITE A WRITE !,"THIS IS NOT DISPLAYED" QUIT ET WRITE !,"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 ERRORET+1^EP8A BAD^EP8A ($ZTRAP) +1^GTM$DMOD (Direct mode) HERE COMES AN ERROR IN THE TRAP CODE %GTM-E-DIVZERO, Attempt to divide by zero 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 EP9 WRITE !,"THIS IS ",$TEXT(+0) SET $ZTRAP="DO ET" KILL A BAD WRITE A WRITE !,"THIS IS NOT DISPLAYED" QUIT ET SET $ZT="" WRITE !,"THIS IS THE ERROR TRAP" ERROR WRITE !,"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-DIVZERO, Attempt to divide by zero %GTM-I-RTSLOC, At M source location ERROR+1^EP9 $
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.
The QUIT, HALT and ZHALT commands also serve as useful $ETRAP or $ZTRAP actions.
The QUIT command terminates execution at that invocation level.
Example:
GTM>zprint ^EP10 EP10 WRITE !,"THIS IS ",$TEXT(+0) SET $ECODE="";this affects only $ETRAP S $ET="S $EC="""" Q" ;this implicitly stacks $ZTRAP ;N $ZT S $ZT="QUIT" ;would give a similar result DO SUB1 QUIT SUB1 WRITE !,"THIS IS SUB1" DO SUB2 WRITE !,"THIS IS SUB1 AFTER THE ERROR WAS 'IGNORED'" QUIT SUB2 WRITE !,"THIS IS SUB2" KILL A BAD WRITE A WRITE !,"THIS IS NOT DISPLAYED" QUIT GTM>do ^EP10 THIS IS EP10 THIS IS SUB1 THIS IS SUB2 THIS IS SUB1 AFTER THE ERROR WAS 'IGNORED' GTM>
This routine sets $ETRAP or $ZTRAP to the QUIT command. When the routine encounters an error at label BAD, GT.M executes the active error handling ISV. The QUIT command terminates execution of SUB2 and transfers execution back to SUB1. The WRITE displays the error message using the $ZSTATUS special variable. Because the default behavior is to QUIT after $ETRAP code completes, this technique is mostly useful with $ETRAP as a place holder to avoid the $ETRAP="" semantics when there is no action to take at the current level. With $ZTRAP, where the default behavior is to resume execution at the beginning the line that triggered the error, the QUIT is more than a placeholder.
The HALT command terminates routine execution and returns control to the shell level. Setting $ETRAP="HALT" or $ZTRAP="HALT" is similar to setting the ISV to the empty string except that the "HALT" code does not pass the error condition code back to the shell. After a HALT, $? contains zero (0).
ZHALT acts like HALT but takes and argument, which GT.M passes back to the OS shell. Note that UNIX shells typically limit return codes to a byte, so they may truncate the value of the ZHALT argument.
Example:
GTM>ZPRINT ^EP11 EP11 WRITE !,"THIS IS ",$TEXT(+0) SET $ECODE="";this affects only $ETRAP SET $ETRAP="HALT";this implicitly stacks $ZTRAP ;SET $ZTRAP="HALT";would give a similar result KILL A BAD WRITE !,A WRITE !,"THIS IS NOT DISPLAYED" QUIT GTM>DO ^EP11 THIS IS EP11 $
Summary of Error-Handling Options | |
---|---|
ERROR-HANDLING FEATURE |
DESCRIPTION AND POSSIBLE USES |
$ETRAP="BREAK" $ZTRAP="BREAK" |
Returns to Direct Mode upon encountering an error that enables interactive debugging to determine the nature of the error. |
$ETRAP="GOTO.." $ZTRAP="GOTO.." |
Transfers control upon encountering an error and allows for continuation of execution after the error. Use with an error handling routine that may record or report an error. |
$ETRAP="ZGOTO.." $ZTRAP="ZGOTO.." |
Similar to GOTO, but additionally allows for removal of levels from the stack. Use to allow recovery to specific point, such as a menu. |
NEW $ETRAP NEW $ZTRAP |
NEW $ETRAP stacks the old value but does not change the current value, while NEW $ZTRAP stacks the old value and sets the current value to the empty string. Usually followed by a SET $ETRAP or SET $ZTRAP. After a QUIT from a given level, GT.M restores the value held prior to the NEW. Use to enable different methods of error handling at different levels within an application. |
$ETRAP="DO..." |
Transfers execution temporarily to another label upon encountering an error. After return from a DO, GT.M QUITs from the stack level at which the error occured. Whether control returns to the invoking code or to the trap handler at the less nested level, depends on the value of $ECODE. |
$ZTRAP="DO..." |
Transfers execution temporarily to another label upon encountering an error. When GT.M returns from a DO and completes the $ZTRAP action, execution continues at the beginning of the line containing the error and re-executes the entire line containing the error. Use with I/O device errors where operator may intervene to correct the error condition. |
$ZTRAP="" |
Returns to shell with the Status Code and terminates execution. If SET in error handling routines, prevents infinite loops. Prevents access to Direct Mode. Use in production code when the invoking shell needs to test $?. |
$ETRAP="SET $ECODE=""""" $ZTRAP="QUIT" |
Terminates execution at that level upon encountering an error, and returns to the invocation level at the point immediately following the invocation. Use to ignore errors on a particular level and continue executing. |
$ZTRAP="HALT" |
Returns to the shell as if normal termination occurred. Avoids access to Direct Mode. Use in production code when the invoking shell does not need to examine the exit status of the GT.M process. |
If $ZTRAP contains invalid source code, GT.M displays an error message and puts the process into Direct Mode.
If the action specified by $ZTRAP results in another run-time error before changing the value of $ZTRAP, it may result in a loop that iteratively invokes $ZTRAP until a stack overflow terminates the GT.M image. Keep $ZTRAP simple and take special care to debug exception handling.
Note | |
---|---|
An error in $ETRAP code triggers an implicit TROLLBACK:$TLEVEL QUIT:$QUIT "" QUIT. |
GT.M provides a number of standard features and extensions to examine and record information about an error condition.
The extensions are:
ZSHOW
ZWRITE
$ECODE
$STACK
$STACK()
$ZSTATUS
$ZJOBEXAM()
$ZLEVEL
The ZSHOW command displays information about the current M environment. A ZSHOW argument may contain an expression that contains codes selecting one or more types of information for output.
A: selects auto-relink information
B: selects ZBREAK information
C: provides the list of loaded external call packages and their routines. ZSHOW "C" does not report packages that are accessible but have not been accessed by the process.
D: selects open device information
G: selects global statistic information
I: selects intrinsic special variables
L: selects locks held by the process
R: selects the M stack but with routine hashes
S: selects the M stack
V: selects local variables
*: selects all possible ZSHOW information except A.
A ZSHOW with no argument displays the M stack on the current device. It lists the program stack from initiation to the current execution level.
The ZWRITE command prints the current value of defined variables. ZWRITE provides a tool for examining or saving variable context. ZWRITE and ZSHOW can only display the current local variables, not any local variable states that have been protected by NEW commands, or appearance in an invoked formallist. A WRITE may also display current global variables.
The $ECODE special variable contains a M standardized/user defined/GT.M specific error code.
The $STACK special variable contains the current level of M execution stack depth.
The $STACK() function returns strings describing aspects of the execution environment.
The $ZLEVEL special variable maintains an integer that indicates the level of nesting of DO and XECUTE commands. $ZLEVEL always contains an integer count of the number of levels displayed by issuing a ZSHOW "S" in that context.
The $ZJOBEXAM() function returns a string indicating the full path to the file where it stored a process context dump.
The $ZSTATUS special variable records the error condition code and location of the last error condition during execution.
For I/O operations, GT.M uses the $ZA, $ZB and $ZEOF special variables. $ZA contains a status determined by the last read on the current device.
To simplify record keeping, an application may set $ZTRAP to an error-handling routine that records information about an error. The next section provides an example of a routine ERR.m that does this.
GTM>ZPRINT ^ERR ERR0;;RECORD CONTENT OF AN ERROR ; RECORD SET $ZTRAP="GOTO OPEN" ZSHOW "*":^ERR($J,$H) GOTO LOOPT;$H might change LOOPV ZSHOW "V":^ERR($J,$H,"VL",$ZLEVEL) LOOPT IF $ZLEVEL>1 ZGOTO $ZLEVEL-1:LOOPV STACK SET $ZTRAP="GOTO WARN" SET %ERRVH=$H;can cause error if memory low SET ^ERR($J,%ERRVH,"$STACK")=$STACK SET ^ERR($J,%ERRVH,"$STACK",-1)=$STACK(-1) FOR %ERRVI=$STACK(-1):-1:1 DO . SET %ERRVK="" . FOR %ERRVJ="PLACE","MCODE","ECODE" DO . . SET %ERRVK=%ERRVK_$STACK(%ERRVI,%ERRVJ)_"|~|" . SET ^ERR($J,%ERRVH,"$STACK",%ERRVI)=%ERRVK GOTO WARN OPEN SET $ZTRAP="GOTO OPEN1" SET %ERRIO=$IO,%ERRZA=$ZA,%ERRZB=$ZB,%ERRZE=$ZEOF SET %ERRVF="REC.ERR" SET %ERRVF=$ZDATE($H,"YEARMMDD2460SS")_"_"_$J_".ERR" OPEN %ERRVF:NEWVERSION USE %ERRVF S $ZT="S $ZT="" G WARN"" U $P:(NOCENA:CTRAP="""") G STAC" ZSHOW "*" KILL %ERRVF,%ERRIO,%ERRZA,%ERRZB,%ERRZE GOTO LOOPU LOOPF WRITE !,"LOCAL VARIABLES FOR ZLEVEL: ",$ZLEVEL,! ZWRITE LOOPU IF $ZLEVEL>1 ZGOTO $ZLEVEL-1:LOOPF WRITE ! STAC SET $ZTRAP="GOTO WARN" WRITE !,"PROGRAM STACK: ",! WRITE !,"$STACK: ",$STACK,! WRITE !,"$STACK(-1): ",$STACK(-1),! FOR %ERRVI=$STACK(-1):-1:1 DO . WRITE !,"LEVEL: ",%ERRVI . SET %ERRVK=10 . FOR %ERRVJ="PLACE","MCODE","ECODE" DO .. W ?%ERRVK,"",%ERRVJ,":",$STACK(%ERRVI,%ERRVJ) .. SET %ERRVK=%ERRVK+20 CLOSE $IO WARN SET $ZTRAP="GOTO FATAL" IF $P=$I SET %ERRIO=$IO,%ERRZA=$ZA,%ERRZB=$ZB,%ERRZE=$ZEOF USE $P:(NOCENABLE:CTRAP="":EXCEPTION="") WRITE !,"YOU HAVE ENCOUNTERED AN ERROR" WRITE !,"PLEASE NOTIFY JOAN Q SUPPORT PERSON",! FATAL SET $ZTRAP="" ZM +$P($ST($ST(-1),"ECODE"),"Z",2)
The routine sets $ZTRAP to a sequence of values so that, in the event of an error various fallback actions are taken. If a STACKCRIT error occurs, GT.M makes a small amount of space for error handling. However, if the error handler uses up significant amounts of space by nesting routines or manupulating local variables, the error handler may cause another STACKCRIT error. In this case, it is possible for the error handling to loop endlessly, therefore this routine changes $ZTRAP so that each error moves the routine closer to completion.
First it attempts to store the context information in the global ^ERR. The LOOPV-LOOPT code records the invocation levels using the ZSHOW command. This technique addresses the situation where the application program defines or NEWs local variables for each level. The code executes a pass through the loop for each instance where the value of $ZLEVEL is greater than one (1). For each pass, ERR.M decrements the value of $ZLEVEL with the ZGOTO. When the value of $ZLEVEL reaches one (1), the code at, and following, the STACK label stores the error context available in the $STACK() function.
If there is a problem with storing any of this information, ^ERR attempts to store the context information in a file in the current default working directory. If it uses a file, in order to (at the label OPEN), record information about I/O operations, on the current device at the time of the error, the error handler SETs local variables to the values of the device specific I/O special variables $IO, $ZA, $ZB and $ZEOF before opening the log file.
The routine OPENs the log file with a name made up of the date and $JOB of the process. The NEWVERSION deviceparameter instructs GT.M to create a new version of the file. The LOOPF-LOOPU code records the invocation levels using the ZWRITE command in a manner analogous to that described above. If an error occurs trying to write to the file, $ZTRAP USEs the principal device and transfers control to the STAC label in an attempt to provide a minimal error context on the user terminal. The code at and following the STAC label records the error context available in the $STACK() function.
At the label WARN, the routine attempts to notify the user that an error has occurred and who to notify.
At the label FATAL, the ZMESSAGE command resignals the error. Because (with proper setup) $ETRAP and $ZTRAP are now null, GT.M releases control of the process to the host shell. In this example, the user never has access to Direct Mode.
Example:
GTM>zprint ^EP13 EP13 WRITE !,"THIS IS ",$TEXT(+0) SET $ZTRAP="GOTO NODB" KILL ^ERR NODB SET $ECODE="";this affects only $ETRAP ;S $ET="GOTO ^ERR";this implicitly stacks $ZTRAP N $ZT S $ZT="GOTO ^ERR" ;gives similar result DO SUB1 WRITE !,"THIS IS THE END" QUIT SUB1 WRITE !,"THIS IS SUB1" NEW SET (A,B,C)=$ZLEVEL DO SUB2 QUIT SUB2 WRITE !,"THIS IS SUB2" NEW SET (B,C,D)=$ZLEVEL DO SUB3 QUIT SUB3 WRITE !,"THIS IS SUB3" NEW SET (A,C,D)=$ZLEVEL DO BAD BAD NEW (A) SET B="BAD" WRITE 1/0 WRITE !,"THIS IS NOT DISPLAYED" QUIT GTM>do ^EP13 THIS IS EP13 THIS IS SUB1 THIS IS SUB2 THIS IS SUB3 YOU HAVE ENCOUNTERED AN ERROR PLEASE NOTIFY JOAN Q SUPPORT PERSON
Example EP13 uses the error recording routine by setting $ZTRAP="GOTO ^ERR". When the routine encounters an error at label BAD, GT.M transfers control to routine ERR. Afterwards the ^ERR global would have contents like:
GTM>zwrite ^ERR ^ERR(13258,"64813,17382","$STACK")=0 ^ERR(13258,"64813,17382","$STACK",-1)=5 ^ERR(13258,"64813,17382","$STACK",1)="NODB+3^EP13|~| DO SUB1|~||~|" ^ERR(13258,"64813,17382","$STACK",2)="SUB1+3^EP13|~| DO SUB2|~||~|" ^ERR(13258,"64813,17382","$STACK",3)="SUB2+3^EP13|~| DO SUB3|~||~|" ^ERR(13258,"64813,17382","$STACK",4)="SUB3+3^EP13|~| DO BAD|~||~|" ^ERR(13258,"64813,17382","$STACK",5)="BAD+2^EP13|~| WRITE 1/0|~|,M9,Z150373210,|~|" ^ERR(13258,"64813,17382","D",1)="/dev/pts/0 OPEN TERMINAL NOPAST NOESCA NOREADS TYPE WIDTH=165 LENG=48 " ^ERR(13258,"64813,17382","G",0)="GLD:*,REG:*,SET:77,KIL:3,GET:0,DTA:0,ORD:0,ZPR:0,QRY:0,LKS:0,LKF:0,CTN:0,DRD:3,DWT:0,NTW:77,NTR:5,NBW:85,NBR:170,NR0:0,NR1:0,NR2:0,N R3:0,TTW:0,TTR:0,TRB:0,TBW:0,TBR:0,TR0:0,TR1:0,TR2:0,TR3:0,TR4:0,TC0:0,TC1:0,TC2:0,TC3:0,TC4:0,ZTR:0,DFL:0,DFS:0,JFL:0,JFS:0" ^ERR(13258,"64813,17382","G",0,1)=",JBB:0,JFB:0,JFW:0,JRL:0,JRP:0,JRE:0,JRI:0,JRO:0,JEX:0,DEX:0,CAT:80,CFE:0,CFS:0,CFT:0,CQS:0,CQT:0,CYS:0,CYT:0,BTD:6,WFR:0,BUS:0,BTS:0,STG:0,KTG:0,ZTG:0,DEXA:0,GLB:0,JNL:0,MLK:0,PRC:0,TRX:0,ZAD:0,JOPA:0,AFRA:0,BREA:0,MLBA:0,TRGA:0,WRL:0,PRG:0,WFL:0,WHE:0,INC:0" ^ERR(13258,"64813,17382","G",1)="GLD:/home/gtc_twinata/staff/nitin/a.gld,REG:DEFAULT,SET:79,KIL:4,GET:0,DTA:0,ORD:0,ZPR:0,QRY:0,LKS:0,LKF:0,CTN:79,DRD:3,DWT:0,NTW:79 ,NTR:6,NBW:87,NBR:178,NR0:0,NR1:0,NR2:0,NR3:0,TTW:0,TTR:0,TRB:0,TBW:0,TBR:0,TR0:0,TR1:0,TR2:0,TR3:0,TR4:0,TC0:0,TC1:0,TC2:0," ^ERR(13258,"64813,17382","G",1,1)="TC3:0,TC4:0,ZTR:0,DFL:0,DFS:0,JFL:0,JFS:0,JBB:0,JFB:0,JFW:0,JRL:0,JRP:0,JRE:0,JRI:0,JRO:0,JEX:0,DEX:0,CAT:83,CFE:0,CFS:0,CFT:0,CQS :0,CQT:0,CYS:0,CYT:0,BTD:6,WFR:0,BUS:0,BTS:0,STG:0,KTG:0,ZTG:0,DEXA:0,GLB:0,JNL:0,MLK:0,PRC:0,TRX:0,ZAD:0,JOPA:0,AFRA:0,BREA:0,MLBA:0,TRGA:0,WRL:0,PRG:0,WFL:0,WHE:0,INC:0" ^ERR(13258,"64813,17382","I",1)="$DEVICE=""""" ^ERR(13258,"64813,17382","I",2)="$ECODE="",M9,Z150373210,""" ^ERR(13258,"64813,17382","I",3)="$ESTACK=5" ^ERR(13258,"64813,17382","I",4)="$ETRAP=""""" ^ERR(13258,"64813,17382","I",5)="$HOROLOG=""64813,17382""" ^ERR(13258,"64813,17382","I",6)="$IO=""/dev/pts/0""" ^ERR(13258,"64813,17382","I",7)="$JOB=13258" ^ERR(13258,"64813,17382","I",8)="$KEY=""""" ^ERR(13258,"64813,17382","I",9)="$PRINCIPAL=""/dev/pts/0""" ^ERR(13258,"64813,17382","I",10)="$QUIT=0" ^ERR(13258,"64813,17382","I",11)="$REFERENCE=""^ERR(13258,""""64813,17382"""",""""I"""",10)""" ^ERR(13258,"64813,17382","I",12)="$STACK=5" ^ERR(13258,"64813,17382","I",13)="$STORAGE=2147483647" ^ERR(13258,"64813,17382","I",14)="$SYSTEM=""47,gtm_sysid""" ^ERR(13258,"64813,17382","I",15)="$TEST=1" ^ERR(13258,"64813,17382","I",16)="$TLEVEL=0" ^ERR(13258,"64813,17382","I",17)="$TRESTART=0" ^ERR(13258,"64813,17382","I",18)="$X=12" ^ERR(13258,"64813,17382","I",19)="$Y=6" ^ERR(13258,"64813,17382","I",20)="$ZA=0" ^ERR(13258,"64813,17382","I",21)="$ZALLOCSTOR=780808" ^ERR(197306,"64341,39400","I",21)="$ZAUDIT=0" ^ERR(13258,"64813,17382","I",22)="$ZB=""""" ^ERR(13258,"64813,17382","I",23)="$ZCHSET=""M""" ^ERR(13258,"64813,17382","I",24)="$ZCLOSE=0" ^ERR(13258,"64813,17382","I",25)="$ZCMDLINE=""""" ^ERR(13258,"64813,17382","I",26)="$ZCOMPILE=""""" ^ERR(13258,"64813,17382","I",27)="$ZCSTATUS=0" ^ERR(13258,"64813,17382","I",28)="$ZDATEFORM=0" ^ERR(13258,"64813,17382","I",29)="$ZDIRECTORY=""/path/to/the/current/directory""" ^ERR(13258,"64813,17382","I",30)="$ZEDITOR=0" ^ERR(13258,"64813,17382","I",31)="$ZEOF=0" ^ERR(13258,"64813,17382","I",32)="$ZERROR=""Unprocessed $ZERROR, see $ZSTATUS""" ^ERR(13258,"64813,17382","I",33)="$ZGBLDIR=""/path/to/the/global/directory""" ^ERR(13258,"64813,17382","I",34)="$ZHOROLOG=""64813,17382,175283,14400""" ^ERR(13258,"64813,17382","I",35)="$ZICUVER=""" ^ERR(13258,"64813,17382","I",36)="$ZININTERRUPT=0" ^ERR(13258,"64813,17382","I",37)="$ZINTERRUPT=""IF $ZJOBEXAM()""" ^ERR(13258,"64813,17382","I",38)="$ZIO=""/dev/pts/0""" ^ERR(13258,"64813,17382","I",39)="$ZJOB=0" ^ERR(13258,"64813,17382","I",40)="$ZKEY=""""" ^ERR(13258,"64813,17382","I",41)="$ZLEVEL=6" ^ERR(13258,"64813,17382","I",42)="$ZMAXTPTIME=0" ^ERR(13258,"64813,17382","I",43)="$ZMODE=""INTERACTIVE""" ^ERR(13258,"64813,17382","I",44)="$ZONLNRLBK=0" ^ERR(13258,"64813,17382","I",45)="$ZPATNUMERIC=""M""" ^ERR(13258,"64813,17382","I",46)="$ZPIN=""/dev/pts/0""" ^ERR(13258,"64813,17382","I",47)="$ZPOSITION=""RECORD+1^ERR""" ^ERR(13258,"64813,17382","I",48)="$ZPOUT=""/dev/pts/0""" ^ERR(13258,"64813,17382","I",49)="$ZPROMPT=""GTM>""" ^ERR(13258,"64813,17382","I",50)="$ZQUIT=0" ^ERR(13258,"64813,17382","I",51)="$ZREALSTOR=802648" ^ERR(13258,"64813,17382","I",52)="$ZRELDATE=""20180614 00:33""" ^ERR(13258,"64813,17382","I",53)="$ZROUTINES="". /usr/lib/fis-gtm/V6.3-007_x86_64 /usr/lib/fis-gtm/V6.3-007_x86_64/plugin/o(/usr/lib/fis-gtm/V6.3-007_x86_64/plugin/r)""" ^ERR(13258,"64813,17382","I",54)="$ZSOURCE=""""" ^ERR(13258,"64813,17382","I",55)="$ZSTATUS=""150373210,BAD+2^EP13,%GTM-E-DIVZERO, Attempt to divide by zero""" ^ERR(13258,"64813,17382","I",56)="$ZSTEP=""B""" ^ERR(13258,"64813,17382","I",57)="$ZSTRPLLIM=0" ^ERR(13258,"64813,17382","I",58)="$ZSYSTEM=0" ^ERR(13258,"64813,17382","I",59)="$ZTIMEOUT=-1" ^ERR(13258,"64813,17382","I",60)="$ZTDATA=0" ^ERR(13258,"64813,17382","I",61)="$ZTDELIM=""""" ^ERR(13258,"64813,17382","I",62)="$ZTEXIT=""""" ^ERR(13258,"64813,17382","I",63)="$ZTLEVEL=0" ^ERR(13258,"64813,17382","I",64)="$ZTNAME=""""" ^ERR(13258,"64813,17382","I",65)="$ZTOLDVAL=""""" ^ERR(13258,"64813,17382","I",66)="$ZTRAP=""GOTO OPEN""" ^ERR(13258,"64813,17382","I",67)="$ZTRIGGEROP=""""" ^ERR(13258,"64813,17382","I",68)="$ZTSLATE=""""" ^ERR(13258,"64813,17382","I",69)="$ZTUPDATE=""""" ^ERR(13258,"64813,17382","I",70)="$ZTVALUE=""""" ^ERR(13258,"64813,17382","I",71)="$ZTWORMHOLE=""""" ^ERR(13258,"64813,17382","I",72)="$ZUSEDSTOR=759855" ^ERR(13258,"64813,17382","I",73)="$ZUT=1528966182176530" ^ERR(13258,"64813,17382","I",74)="$ZVERSION=""GT.M V6.3-007 Linux x86_64""" ^ERR(13258,"64813,17382","I",75)="$ZYERROR=""""" ^ERR(13258,"64813,17382","L",0)="MLG:0,MLT:0" ^ERR(13258,"64813,17382","R",1)="RECORD+1^ERR:e99b16e4f7e1112d058dc22cb53491fd" ^ERR(13258,"64813,17382","R",2)="SUB3+3^EP13:d9e026c6d14e42567d3e64eecd049726" ^ERR(13258,"64813,17382","R",3)="SUB2+3^EP13:d9e026c6d14e42567d3e64eecd049726" ^ERR(13258,"64813,17382","R",4)="SUB1+3^EP13:d9e026c6d14e42567d3e64eecd049726" ^ERR(13258,"64813,17382","R",5)="NODB+3^EP13:d9e026c6d14e42567d3e64eecd049726" ^ERR(13258,"64813,17382","R",6)="+1^GTM$DMOD (Direct mode) " ^ERR(13258,"64813,17382","V",1)="A=5 ;*" ^ERR(13258,"64813,17382","V",2)="B=""BAD""" ^ERR(13258,"64813,17382","VL",3,"V",1)="A=3" ^ERR(13258,"64813,17382","VL",3,"V",2)="B=3" ^ERR(13258,"64813,17382","VL",3,"V",3)="C=3" ^ERR(13258,"64813,17382","VL",4,"V",1)="B=4" ^ERR(13258,"64813,17382","VL",4,"V",2)="C=4" ^ERR(13258,"64813,17382","VL",4,"V",3)="D=4" ^ERR(13258,"64813,17382","VL",5,"V",1)="A=5" ^ERR(13258,"64813,17382","VL",5,"V",2)="C=5" ^ERR(13258,"64813,17382","VL",5,"V",3)="D=5"