Pages

Thursday, June 27, 2013

CL does DO

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.

8 comments:

  1. I am reposting this from a thread I created on LinkedIn. The comment was posted by Livio Daneluzzi (Milan Italy):
    << 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!" >>

    ReplyDelete
  2. Excelent post!
    It was very useful.

    ReplyDelete
  3. This is really helpful. Especially the LEAVE command, I've read it for the first time.

    ReplyDelete
  4. In 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.

    ReplyDelete
  5. Pet peeve #1,001 is when GOTO is used to exit a DO loop (rather than leave or iterate)

    ReplyDelete
  6. Simon, Thanks for sharing. I hated the goto branching cmd . I was used wildly in the 80s. Great read.

    ReplyDelete
  7. Reynaldo Dandreb MedillaMarch 31, 2022 at 5:10 AM

    Yeah Simon, and add to that the callsubr for executing a subroutine, it would make the cl pgm a well structured code

    ReplyDelete

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.