If you go to MC Press’ Online store at www.mc-store.com and search for CL PROGRAMMING you’ll get a list of books and courses/tutorials that may help.
If you can program in any language then picking up CL won’t be difficult. Here’s a simple example to point out the basics and essentials of a CL program:
PGM PARM(&FILE &LIB)
/* Declare all fields (including parameters)… */
DCL VAR(&FILE) TYPE(*CHAR) LEN(10)
DCL VAR(&LIB) TYPE(*CHAR) LEN(10)
DCL VAR(&IX) TYPE(*DEC) LEN(5 0) VALUE(0)
DCL VAR(&MSGTXT) TYPE(*CHAR) LEN(512)
DCL VAR(&FLDNO) TYPE(*CHAR) LEN(5)
/* Declare any files used by the program… */
/* Global error handling… */
/* Check that a filename was passed… */
IF COND(&FILE *EQ ‘ ‘) THEN(DO)
SNDPGMMSG MSG(‘File name must not be blank’)
/* If a library wasn’t passed then we can default to *LIBL… */
IF COND(&LIB *EQ ‘ ‘) THEN(CHGVAR VAR(&LIB) +
/* Build a file in QTEMP containing a list of fields in the specified file… */
DSPFFD FILE(&LIB/&FILE) OUTPUT(*OUTFILE) +
OVRDBF FILE(QADSPFFD) TOFILE(QTEMP/FIELDS) +
/* Read through the file and send a message to the user for each field found */
/* in the file… */
MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(ENDLOOP))
/* Build the message to send to the user… */
CHGVAR VAR(&IX) VALUE(&IX + 1)
CHGVAR VAR(&FLDNO) VALUE(&IX)
CHGVAR VAR(&MSGTXT) VALUE(&FLDNO *CAT ‘) ‘ *CAT ‘ +
‘ *CAT &WHFLDI *CAT %SST(&WHFTXT 1 30))
/* Send the message and repeat the loop… */
/* End of file reached so delete the override and end the program… */
ENDLOOP: DLTOVR FILE(QADSPFFD) LVL(*JOB)
So working through the program you will see that it begins and ends with PGM and ENDPGM statements. The PGM statement allows you to name any parameters you might want your program to use.
Next is the declaration section of the program and here you will find DCL and DCLF statements. The DCL statement is used to define all of the fields used by your program that aren’t defined anywhere else. Fields can be *CHAR, *DEC or *LGL (logical). You’ll notice that one of the DCL statements has a VALUE assigned. This initialises the field at run time and is only allowed on non-parameter fields.
The DCLF stands for Declare File and lets you define a file to be used by the CL program. For a long time there was a limit of one file per CL program although that has changed with more recent (v5r3?) versions of the operating system.
MONMSG stands for “Monitor for Messages” and you can either monitor for specific messages or groups of messages. Specifying CPF0000 means monitor for any message beginning with CPF. You can assign specific actions to be performed when messages occur, error handling, but in this simple example we’re just going to ignore them. You can have multiple MONMSG’s in a row, because this one is the first thing after the declares then it applies to every command/statement in the program.
Next we have a couple of conditions, testing whether the input parameters are blank. If the file name is blank we send a message to appear at the bottom of the users display and exit the program.
If the library is blank then we’re using the CHGVAR command to change the value of a variable. The CHGVAR command is used extensively in CL programming.
Note, the difference between the two conditions and resulting THEN() operations. The first one has THEN(DO) which tells the system that you want to perform a number of commands, and indeed all commands up to and including the ENDDO are associated with the condition of the IF being true.
Next we run the DSPFFD (Display File Field Descriptions) command to generate a file called FIELDS in library QTEMP. This file will contain a list of all fields found in the definition of the file specified in variable &FILE. Note, though, that the name is not the same as the file that was declared on the DCLF statement.
The reason for this is that the operating system contains a template file for each command that can generate *OUTFILE’s. For the DSPFFD command it’s file QADSPFFD. For any command on the system you can press F4 to prompt it and then move the cursor to the title on line 1 and press F1 to see a) the template file it uses (if any) and b) the messages that can be monitored for it. This is very useful.
So, to tell the system to use the file we created we call the OVRDBF (Override Database File) command which tells the system that any time it’s told to use QADSPFFD it should use FIELDS in QTEMP instead.
We’re now ready to start reading through the file and for this we use the RCVF (Receive Format) command. Notice the LOOP: at the left hand side? This is a tag which can be referenced using the GOTO command. A tag is always on the left hand side and ends with a colon (‘:’) character. Again, until recently we only had the GOTO command for controlling loops.
After the RCVF we have another MONMSG command where we monitor for CPF0864 being generated. CPF0864 is the message ID that means “End of file detected” and by placing the MONMSG after the RCVF it only applies to the RCVF command. We could have put the MONMSG at the top of the program after the MONMSG CPF000 and it would still work. It wouldn’t, however, be as intuitive when looking at the program source.
Next we have three CHGVAR commands. The first shows how to do maths on a numeric field, the second puts the contents of a numeric field into a character field and the third concatenates character fields/values together.
There are three types of string concatenation you can use; *CAT, *BCAT, *TCAT. *CAT just joins the two strings together, *BCAT removes leading blanks from the second string and *TCAT removes trailing blanks from the first string. These can be shortened to use ||, ‘<|’ and ‘|>’ respectively but I prefer to use the *CAT, etc.
Also in the third CHGVAR you’ll see %SST(&WHFTXT 1 30) this is a very commonly used function that lets you extract substrings from fields. In this case I’m taking the 30 characters that begin in position 1 of field &WHFTXT.
Field &WHFTXT? Where did that come from? We didn’t declare it! Actually we did, by declaring file QADSPFFD the system automatically brings in all fields from the file definition. We can reference these fields by placing an ampersand (‘&’) in front of the field name. All fields in CL start with an ampersand character.
Having built field &MSGTXT we can send it to the user before closing the loop with a GOTO to go back and retrieve the next record.
When the end of the file is reached we jump to the ENDLOOP where we delete the override to tidy up and then end the program. Sometimes you’ll see a RETURN before the ENDPGM, but it isn’t necessary.
You can use more or less all commands on the AS/400 within a CL program and you can write fairly complicated programs with it too. It does have it’s limitations, but for 98% of cases you’ll find you can quite easily achieve what you want to do with it. Having said that, it’s not RPG or COBOL so don’t expect to write file maintenance utilities, etc, with it.
I hope the example gives you a taste of what can be done and somewhere to start from.
All the best