When programming on IBM i, message handling is always a part. Like programming exceptions, messages need to be captured and handled appropriately. This is more obvious in CL language on AS400(currently IBM i). Like the patter of “try…catch”, command MONMSG is used to monitor and capture messages.
Though MONMSG is a CL command, but it can only be used in a program, but not an interactive job. MONMSG is used in nearly every CL program. By using MONMSG correctly and skillfully, many wonderful functions can be implemented.
Here is an example.
0001.00 PGM
0002.00 DCL &A *INT VALUE(5)
0003.00 DCL &B *INT VALUE(0)
0004.00 CHGVAR VAR(&A) VALUE(&A / &B)
0005.00 ENDPGM
Obviously, there is an error of zero divide. When this program runs, there will be an exceptional message(MCH1211) and users are asked to handle it. How to continue the run of the program even after this exception, but not interrupt users?
Here is the MONMSG.
0004.00 CHGVAR VAR(&A) VALUE(&A / &B)
0005.00 MONMSG MSGID(MCH1211)
With new line 5, MONMSG is after CHGVAR, with MSGID specified, MCH1211 is captured. When program is executed here, it is not interrupted and users don’t have to handle it immediately.
How can we add some message handling for MCH1211?
0004.00 CHGVAR VAR(&A) VALUE(&A / &B)
0005.00 MONMSG MSGID(MCH1211) EXEC(CHGVAR VAR(&A) VALUE(1))
Keywork EXEC is added to line 5 together with a line of message handling, after MONMSG. When zero divide happens, the result value(variable A) is set to 1. This way, we have message capture and error handling.
Taking this one step further, how to get this message out of joblog? Actually, we can remove it from the joblog. Here is the code.
0004.00 CHGVAR VAR(&A) VALUE(&A / &B)
0005.00 MONMSG MSGID(MCH1211) EXEC(QSYS/DO)
0006.00 CHGVAR VAR(&A) VALUE(1)
0007.00 QSYS/RCVMSG PGMQ(*SAME *) MSGTYPE(*LAST) RMV(*YES)
0008.00 QSYS/ENDDO
In the snippet between DO and ENDO, once MCH1211 is captures, after the error handling, RCVMSG is called, with its parameter RMV set to ‘*YES’, thus the message is removed from the joblog. Just like the message MCH1211 is never there.
One popular scenario of removing messages is that when we delete an object, it is not on the system. The purpose of deleting this object is to make sure it is not on the system. Here we don’t want any messages about ‘object does not exist’(CPF2105). We can put it this way.
0003.00 QSYS/DLTF FILE(NONLIB/NONFILE)
0004.00 MONMSG MSGID(CPF2105) EXEC(QSYS/DO)
0005.00 QSYS/RCVMSG PGMQ(*SAME *) MSGTYPE(*LAST) RMV(*YES)
0006.00 QSYS/ENDDO
If there are many divide operations with the same message handling, this code snippet needs to put after each one. In this case, a global MONMSG is very helpful. The MONMSG is written once, but effects globally. Here is the code.
0001.00 PGM
0002.00 DCL &A *INT VALUE(5)
0003.00 DCL &B *INT VALUE(0)
0004.00 DCL &C *INT VALUE(0)
0005.00 MONMSG MSGID(MCH1211) EXEC(GOTO EXITPGM)
0006.00 CHGVAR VAR(&A) VALUE(&A / &B)
0007.00 CHGVAR VAR(&A) VALUE(&A / &C)
0008.00 EXITPGM:
0009.00 CHGVAR VAR(&A) VALUE(1)
0010.00 QSYS/RCVMSG PGMQ(*SAME *) MSGTYPE(*LAST) RMV(*YES)
0011.00 ENDPGM
In global MONMSG, only GOTO can be executed in EXEC, so a label is needed and error handling code is after this label.