CL Programming Explained

CL, short for Control Language, is the command language of IBM i. Every command you type on a command line is CL, and a CL program is a sequence of those commands with variables, decisions and error handling around them. It is the orchestration layer: it runs commands, calls programs, submits jobs and reacts when something fails. Large business logic usually belongs in RPGLE or another application language.

Commands Are the Building Blocks

A CL command is a verb and an object, written in capitals by convention, followed by named parameters:

CRTLIB LIB(DEMOLIB) TEXT('Demo library')
DSPLIBL
WRKACTJOB

The prefix tells you the action (CRT create, CHG change, DLT delete, DSP display, WRK work with, ADD, RMV, STR start, END end) and the rest names the thing. Press F4 on any command to prompt it, and F1 for help on a parameter. Most CL commands are the same ones you use interactively, which is why CL feels natural once you know the platform.

A Small CL Program

CL source goes in a source member of type CLLE. This program clears a work file, copies data into it and reports what happened:

PGM PARM(&RUNDATE)
  DCL VAR(&RUNDATE) TYPE(*CHAR) LEN(8)
  DCL VAR(&USER)    TYPE(*CHAR) LEN(10)

  RTVJOBA USER(&USER)

  /* Remove yesterday's work file; ignore "file not found" */
  DLTF FILE(QTEMP/WORKORD)
  MONMSG MSGID(CPF2105)

  CRTDUPOBJ OBJ(ORDERS) FROMLIB(PRODLIB) OBJTYPE(*FILE) +
            TOLIB(QTEMP) NEWOBJ(WORKORD) DATA(*NO)
  MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(FAILED))

  CALL PGM(APPLIB/BLDORDERS) PARM(&RUNDATE)
  MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(FAILED))

  SNDPGMMSG MSG('Order build finished for ' *CAT &RUNDATE *CAT ' by ' *CAT &USER) +
            TOPGMQ(*EXT)
  RETURN

FAILED:
  SNDPGMMSG MSG('Order build failed. See the job log.') TOPGMQ(*EXT)
  RETURN
ENDPGM

Compile it into a program object and run it:

CRTBNDCL PGM(APPLIB/ORDBUILD) SRCFILE(APPLIB/QCLLESRC) SRCMBR(ORDBUILD)
CALL PGM(APPLIB/ORDBUILD) PARM('20261005')

Points to notice:

  • PGM and ENDPGM frame the program, and PARM(&RUNDATE) declares the parameter. The variable is declared with DCL and is typed: *CHAR, *DEC, *INT, *LGL.
  • Variables begin with &. CHGVAR assigns values, and *CAT joins strings.
  • RTVJOBA retrieves attributes of the current job into variables. The RTV commands are how CL reads information.
  • MONMSG handles errors (below).
  • QTEMP is a library private to the job, which makes it a good place for work files.

Flow Control

CL has the usual structures, with commands rather than keywords:

IF COND(&RC *EQ 0) THEN(DO)
  /* success */
ENDDO
ELSE DO
  /* failure */
ENDDO

DOWHILE COND(&COUNT *LT 5)
  CHGVAR VAR(&COUNT) VALUE(&COUNT + 1)
ENDDO

SELECT
  WHEN COND(&TYPE *EQ 'A') THEN(CALL PGM(DOA))
  OTHERWISE CMD(CALL PGM(DOOTHER))
ENDSELECT

Comparisons use *EQ, *NE, *LT, *GT, *LE, *GE, and logical operators are *AND, *OR, *NOT. GOTO CMDLBL(label) jumps to a label, which is how the error paths in the earlier example work.

Handling Errors with MONMSG

Every failing command sends an escape message, such as CPF2105 (“file not found”), to the program. If nothing monitors for it, the program stops with an inquiry message that waits for an operator. MONMSG tells CL what to do instead:

  • Placed directly after a command, it covers that command: MONMSG MSGID(CPF2105) ignores the error, or MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(FAILED)) branches.
  • CPF0000 is a generic ID that matches every CPF message, which makes it handy for a catch-all.
  • Placed straight after PGM and the declarations, with no EXEC, it covers the whole program.

Catching everything quietly hides real problems, so monitor for the specific message when you can and log the rest. The CL error handling guides on this site go into message types, RCVMSG and structured patterns: start with IBM i Message Files, Exception Handling and CL.

Running Work in the Background

Batch work is usually submitted rather than run in your session:

SBMJOB CMD(CALL PGM(APPLIB/ORDBUILD) PARM('20261005')) JOB(ORDBUILD) JOBQ(QBATCH)

SBMJOB queues the command as a separate job. To run work on a schedule instead, use job schedule entries; see IBM i Job Scheduling.

Variables and Data Types

CL variables are declared before use and are typed. The ones you will use most:

TypeUse
*CHARText, with a length: DCL VAR(&NAME) TYPE(*CHAR) LEN(30)
*DECPacked numbers: DCL VAR(&AMT) TYPE(*DEC) LEN(9 2)
*INTWhole numbers
*LGLLogical, '1' or '0': DCL VAR(&OK) TYPE(*LGL) VALUE('0')

Variables are not case sensitive and names can be up to 10 characters after the &. A program parameter is a variable too, and parameters are passed by reference, so a called program can change a value you pass it. Declare a parameter with the length the caller uses: a mismatch is a classic source of truncated or garbled values.

Seeing What Happened

When a CL program fails, the job log is the first place to look:

DSPJOBLOG
WRKJOB OPTION(4)

For a batch job, the job log is written to a spooled file, which you can open with WRKSPLF. To step through a CL program, compile it with a debug view and start debug before running it:

CRTBNDCL PGM(APPLIB/ORDBUILD) SRCFILE(APPLIB/QCLLESRC) SRCMBR(ORDBUILD) DBGVIEW(*SOURCE)
STRDBG PGM(APPLIB/ORDBUILD)

Adding SNDPGMMSG calls at key points, as in the example, makes the job log tell the story of a run, which saves time later.

Good Habits

  • Put one job’s work in one program and give it a clear name.
  • Monitor for specific messages and let unexpected ones fail loudly.
  • Keep business rules out of CL; call RPG or SQL for them.
  • Use QTEMP for work objects and clean them up at the start, as the example does.
  • Send a completion or failure message that an operator can find.

Passing Parameters Between Programs

CALL passes parameters positionally, and the called program declares them in the same order. A CL program can call another CL program, an RPG program, or a program in any other ILE language.

PGM
  DCL VAR(&CUSTNO) TYPE(*CHAR) LEN(8) VALUE('00012345')
  DCL VAR(&STATUS) TYPE(*CHAR) LEN(1)

  CALL PGM(APPLIB/CUSTCHECK) PARM(&CUSTNO &STATUS)
  IF COND(&STATUS *EQ 'E') THEN(SNDPGMMSG MSG('Customer check failed') TOPGMQ(*EXT))
ENDPGM

The called program receives the address of each value, not a copy. If it changes &STATUS, the caller sees the change. That is useful for returning a result and dangerous if the lengths do not match, so keep parameter definitions in one place, such as a shared copy member for RPG callers.

Commands You Will Use Every Week

  • WRKACTJOB and WRKJOB to see running jobs, and DSPJOBLOG for what a job did.
  • WRKOUTQ and WRKSPLF for spooled output.
  • DSPLIBL, ADDLIBLE and WRKOBJ for the object model.
  • CPYF to copy data between files, and DLTF, CRTPF for file work.
  • CHGVAR, RTVJOBA, RTVSYSVAL to read and set values inside a program.
  • SBMJOB, HLDJOB, RLSJOB, ENDJOB to control batch work.

Each of these is documented in IBM’s CL command reference, and F4 shows the parameters on your own release.

Where CL and RPGLE Meet

A common pattern is a thin CL program around an RPGLE program: CL sets the library list, overrides files, calls the RPG program, checks for errors and sends the result to operators. The RPG program does the business logic and CL does the plumbing. That separation keeps both simple.

Summary

CL is the glue of IBM i. It runs the same commands you type, adds typed variables, flow control and MONMSG error handling, and submits work with SBMJOB. Write small programs that call your RPG or SQL, check every step, and say clearly when something fails.

Learning Path

  1. Command syntax and prompting (F4, F1).
  2. Calling programs and passing parameters.
  3. Variables, CHGVAR, and the RTV commands.
  4. Flow control and MONMSG.
  5. SBMJOB, job queues and scheduling.
  6. Message handling in depth.

Keep reading with IBM i Libraries, Objects, and Members Explained if the object names above are unfamiliar.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top