This time, we're going to improve the way error messages are returned to the calling program or user.
Currently, we're sending back responses using the DSPLY op-code. Yuck. Blech. Ewww.
Instead, error messages should be sent back to the calling program using a typical AS/400 *ESCAPE message! This way, the program that called us will know that we ended abnormally, and can even monitor for a message to handle.
The most convienient way to implement this is to create a subprocedure that gives us a simple interface to the QMHSNDPGM (Send Program Message) API. The subprocedure will fill in all of the details that the API needs, except the actual message data -- we'll pass the message data as a parm.
The result is a subprocedure that looks like this:
P die B D die PI D peMsg 256A const D SndPgmMsg PR ExtPgm('QMHSNDPM') D MessageID 7A Const D QualMsgF 20A Const D MsgData 256A Const D MsgDtaLen 10I 0 Const D MsgType 10A Const D CallStkEnt 10A Const D CallStkCnt 10I 0 Const D MessageKey 4A D ErrorCode 32766A options(*varsize) D dsEC DS D dsECBytesP 1 4I 0 INZ(256) D dsECBytesA 5 8I 0 INZ(0) D dsECMsgID 9 15 D dsECReserv 16 16 D dsECMsgDta 17 256 D wwMsgLen S 10I 0 D wwTheKey S 4A c eval wwMsgLen = %len(%trimr(peMsg)) c if wwMsgLen<1 c return c endif c callp SndPgmMsg('CPF9897': 'QCPFMSG *LIBL': c peMsg: wwMsgLen: '*ESCAPE': c '*PGMBDY': 1: wwTheKey: dsEC) c return P E
Now, instead of code that looks like this:
c eval sock = socket(AF_INET: SOCK_STREAM: c IPPROTO_IP) c if sock < 0 c eval msg = %str(strerror(errno)) c dsply msg c return c endif
We'll make our error handling look more like this:
c eval sock = socket(AF_INET: SOCK_STREAM: c IPPROTO_IP) c if sock < 0 c callp die('socket(): ' + %str(strerror(errno))) c return c endif
Cute, huh? The die() procedure will cause it to send back an escape message when the socket() API fails. The format of the parms in the die() subprocedure makes it very easy to insert into our code.
Having said that, however, here's a slightly more complicated usage:
C if connect(sock: p_connto: addrlen) < 0 c eval err = errno c callp close(sock) c callp die('connect(): '+%str(strerror(err))) c return c endif
The close() API is a UNIX-type API and can return an error via errno just like the connect() API can! Therefore, we save the value of errno before calling close() just to make sure that we don't lose the value.
You should also note that the 'die' procedure will actually end the program. Unless something goes wrong with the 'die' procedure, the 'return' statement will never be executed. This means that if you have something to close, such as a socket, you need to make sure you do it before calling 'die'.
I'll now go through and replace DSPLY with die() throughout my program.