Two of the Command Language, CL, commands added to IBM i (AS400) release V5R3 were the DOWHILE and DOUNTIL, and IBM i 6.1 brought us the DOFOR. I have always wanted DO commands as I have resented not being able to write "structure code" in CL as I had to use the GOTO command to create a loop.
I quickly adopted the DOWHILE into my programming, but I have been surprised that, despite bringing it to their attention, that only one of my colleagues uses it. Which is one of the reasons I wanted to create this post to make sure others are aware of them.
Prior to using these command if I wanted to read a file in a CL I had to do something like:
01 PGM 02 03 DCLF FILE(QTEMP/WRKFILE) OPNID(A) 04 05 LOOP: RCVF OPNID(A) 06 MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ENDLOOP)) 07 08 IF COND(&A_STATUS *NE 'A') + 09 THEN(GOTO CMDLBL(LOOP)) 10 11 ENDLOOP: 12 13 ENDPGM |
Why do I do that? I always use the OPNID parameter on the Declare File, DCLF, command (line 3) to make it easier to understand which of the fields come from the file (see line 8).
Now my code can look like this:
010 PGM 02 03 DCL VAR(&LOOP) TYPE(*LGL) VALUE('1') 04 DCLF FILE(QTEMP/WRKFILE) OPNID(A) 05 06 DOWHILE COND(&LOOP) 07 RCVF OPNID(A) 08 MONMSG MSGID(CPF0000) EXEC(LEAVE) 09 10 IF COND(&A_STATUS *NE 'A') THEN(ITERATE) 11 12 13 ENDDO 14 15 ENDPGM |
Notice that the DOWHILE is conditioned by the field &LOOP, which a Logic type field, and providing it is "on" it will loop.
This code shows two other new CL commands, ITERATE and LEAVE. I am sure you are fully familiar with them in RPGLE, but there is one extra feature they have in CL that I will mention at the bottom of this post.
Why do I do that? I indent my code, which, in my opinion, makes it easier for someone else to read and understand.
If I need to perform a section of code a number of times I would have done something like this:
01 PGM 02 03 DCL VAR(&COUNT) TYPE(*DEC) LEN(2 0) VALUE(1) 04 05 LOOP: 06 07 08 CHGVAR VAR(&COUNT) VALUE(&COUNT + 1) 09 IF COND(&COUNT <= 10) + 10 THEN(GOTO CMDLBL(LOOP)) 11 ENDPGM |
If I used the DOUNTIL command I can do this:
01 PGM 02 03 DCL VAR(&COUNT) TYPE(*DEC) LEN(2 0) VALUE(1) 04 05 DOUNTIL COND(&COUNT > 10) 06 07 08 CHGVAR VAR(&COUNT) VALUE(&COUNT + 1) 09 ENDDO 10 11 ENDPGM |
With the introduction of the DOFOR I use it instead:
01 PGM 02 03 DCL VAR(&COUNT) TYPE(*INT) LEN(2) 04 05 DOFOR VAR(&COUNT) FROM(1) TO(10) 06 07 08 ENDDO 09 10 ENDPGM |
Notice that te &COUNT field has to be defined as a integer, *INT.
The DOFOR works in the same way as the FOR operation code in RPGLE. It initializes the &COUNT field with the value of 1, FROM parameter. Each time it is executed it increments the &COUNT field by 1. When it reaches 10, parameter TO, it executes the DO one more time then leaves. If you want to increment &COUNT by more than one you can use the BY parameter to give the value by which it will be incremented.
Now what is that extra featrure I mentioned that the ITERATE and LEAVE has?
01 PGM 02 03 DCL VAR(&LOOP) TYPE(*LGL) VALUE('1') 04 DCL VAR(&COUNT) TYPE(*INT) LEN(2) 05 DCL VAR(&FLG) TYPE(*CHAR) LEN(1) 06 07 LOOP1: DOWHILE COND(&LOOP) 08 LOOP2: DOFOR VAR(&COUNT) FROM(1) TO(10) 09 10 IF COND(&FLG = '2') + 11 THEN(ITERATE CMDLBL(LOOP2)) 12 13 LEAVE CMDLBL(LOOP1) 14 ENDDO 15 ENDDO 16 17 ENDPGM |
Both ITERATE and LEAVE have the parameter CMDLBL. In the example below when the ITERATE is executed, on line 11, it iterates to the DO with that command label, in this case the first one, DOWHLE exiting the DOFOR. The LEAVE, on line 13, will leave both the DOFOR and DOWHILE.
I have tested this with program created from both CLP and CLLE source members, and it works in both.
You can learn more about the following commands from the IBM website:
This article was written for IBM i 7.1, and it should work with earlier releases too.
I am reposting this from a thread I created on LinkedIn. The comment was posted by Livio Daneluzzi (Milan Italy):
ReplyDelete<< This reminds me, when I was at University, my old IT professor told us: "the difference between a good and a bad programmer is only in a word: GOTO!" >>
Excelent post!
ReplyDeleteIt was very useful.
This is really helpful. Especially the LEAVE command, I've read it for the first time.
ReplyDeleteIn 1980 I read a book "Structured Programming in Cobol". I immediately started replacing "GO TO" with "PERFORM" statements, and never wrote a paragraph more than one screen length.
ReplyDeletePet peeve #1,001 is when GOTO is used to exit a DO loop (rather than leave or iterate)
ReplyDeleteSimon, Thanks for sharing. I hated the goto branching cmd . I was used wildly in the 80s. Great read.
ReplyDeleteYeah Simon, and add to that the callsubr for executing a subroutine, it would make the cl pgm a well structured code
ReplyDeleteSubroutines in CL
Delete