When was the last time you wanted to write a subroutine in your CL program to cut down the amount of code you're...
writing? Or use a logic more complex then "IF/THEN/ELSE" within your CL program? When was the last time you wanted to loop through something without the use of GOTO's and IF's in the clunkiest use of code you've seen in a while. For me, it's daily. Who wants to clean up some code so our business rules and our code look related?
Starting in V5R3, there were significant changes to the organization of CL programming languages:
- New looping methods
- Until loop – DOUNTIL (ENDDO)
- For loop – DOFOR (ENDDO)
- While Loop – DOWHILE (ENDDO)
- Logical end and restart of loops
- ITERATE (same as RPG ITER)
- LEAVE – (same as RPG LEAVE)
- Multiple file declaration (V5R3)
- RCVF for up to five files
- Flow changes
- SELECT when
- Subroutines (V5R4)
DO/ENDDO vs DOUNTIL
Let me show you what you've been missing. In our old routines, we needed to group commands together using DO/ENDDO
DCLF FILE(*LIBL/FILE1) OPNID(ID1)
RCVF OPNID(ID1) /* CPF0864 End of file detected for file &1 in &2. */ MONMSG MSGID(CPF0864) EXEC(DO) ENDDO GOTO CMDLBL(AGAIN)
In a word: Yuck. What if this looked like this?
DCLF FILE(*LIBL/FILE1) OPNID(ID1) DCL VAR(&IMDONE) TYPE(*CHAR) LEN(1) VALUE('0')
DOUNTIL COND(&IMDONE *EQ '1') RCVF OPNID(ID1) /* CPF0864 End of file detected for file &1 in &2. */ MONMSG MSGID(CPF0864) EXEC(LEAVE)ENDDO CALL PGM(MENEXT)
Program flow is cleaned up.
DOUNTIL checks the logic after the first iteration so we'll try and read the file, and leave the loop when the file is completed.
Controlling patterns using DOWHILE
You can control the patterns of your CL programs using
DOWHILE as follows:
DCLF FILE(*LIBL/FILE1) OPNID(ID1) DCL VAR(&FIL2FND) TYPE(*CHAR) LEN(1) VALUE('JHANCOCK') DCL VAR(&FILEFND) TYPE(*CHAR) LEN(1) VALUE('1')
RTVOBJD OBJ(&FILE2FND) OBJTYPE(*FILE) MONMSG MSGID(CPF9801) EXEC(CHGVAR VAR(&FILE2FND) + VALUE('0'))DOWHILE COND(&FILEFND *EQ '1') RCVF OPNID(ID1) MONMSG MSGID(CPF0864) EXEC(LEAVE)ENDDO CALL PGM(MENEXT)
I'm never going to perform the loop unless JHANCOCK is found. Once I reach the end of file in all of these examples, I leave the loop. I can pop back up to the top of the loop if my logic requires me to start with, for example, the next record in the file.
Setting the number of loops
DOFOR is for looping a set amount of times, then falling out of the loop. Say if you need to do something 15 times:
DOFOR VAR(&CTR) FROM(1) TO(15) BY(1)
The static values can be substituted for field names – from
&TO is a valid loop as well.
The examples I gave above also show how to uniquely identify up to five files – display or database files.
Using SELECT/WHEN/END/SELECT to clean up programs
So how many of our programs look like this?
IF COND(%SST(&FILENM 1 3) *EQ 'AAA') THEN(DO)
GOTO CMDLBL(LOOPTOP) ENDDO ELSE CMD(IF COND(%SST(&FILENM 1 3) *EQ 'BBB') + THEN(DO))GOTO CMDLBL(ENDOFLOOP) ENDDO
A little ugly. So we can clean it up:
SELECT WHEN COND(%SST(&FILENM 1 3) *EQ 'AAA') THEN(ITERATE) WHEN COND(%SST(&FILENM 1 3) *EQ 'BBB') THEN(LEAVE) ENDSELECT
DO/ENDDO grouping of code above may be a bit exaggerated. But, you can see that using the
SELECT/WHEN/ENDSELECT your code looks so much easier to understand.
Using CL subroutines
Subroutines clean up the code even more.
SELECT WHEN COND(%SST(&FILENM 1 3) *EQ 'AAA') + THEN(CALLSUBR SUBR(AAAFILE)) WHEN COND(%SST(&FILENM 1 3) *EQ 'BBB') + THEN(CALLSUBR SUBR(BBBFILE)) ENDSELECT
RCLRSC SUBR SUBR(AAAFILE)ENDSUBR ENDPGM
You see that subroutine
AAAFILE is called
WHEN AAA is in the prefix of the field &FILENM. (%SST is the substring command.)
Using this technique, your code will clean up, and you'll be writing shorter and shorter CL programs in no time.