Module 4: CLIST Advanced
CLIST- Advanced
Production CLISTs need more than WRITE and IF: they trap errors instead of dying mid-run, share data between nested CLISTs, live in managed SYSPROC libraries, and cooperate with REXX and ISPF. This module puts those pieces together in one complete utility CLIST.
ERROR handling
- The ERROR statement sets a trap that runs when a TSO command invoked by the CLIST fails.
- ERROR DO ... END runs your own cleanup block: log the failure, then EXIT with a code.
- ERROR RETURN sends control back to the calling CLIST or TSO.
- ERROR EXIT CODE(n) ends the CLIST at once with return code n.
- ERROR OFF disables the trap again. Code the ERROR statement before the risky commands.
PROC 1 DSN
CONTROL NOMSG
ERROR DO
WRITE *** COMMAND FAILED, LASTCC = &LASTCC
EXIT CODE(12)
END
DELETE '&DSN'
WRITE DELETE COMPLETED
EXIT
CONTROL NOMSG
ERROR DO
WRITE *** COMMAND FAILED, LASTCC = &LASTCC
EXIT CODE(12)
END
DELETE '&DSN'
WRITE DELETE COMPLETED
EXIT
GLOBAL and NGLOBAL variables
- Normally each CLIST has its own private variables. GLOBAL &V1 &V2 shares the listed variables with every CLIST it calls, down the whole chain.
- Code GLOBAL right after PROC, before any statement that uses the shared variables.
- Every CLIST in the chain that touches the shared variables should declare the same GLOBAL statement.
- NGLOBAL &V1 removes a variable from the shared pool again.
- Use GLOBAL for a small set of control values (like &HLQ or &DEBUG); pass everything else as PROC arguments.
/* MAIN: shares &HLQ with the CLIST it calls */
PROC 0
GLOBAL &HLQ
SET &HLQ = USER1
EXEC 'USER1.CLIST(SUB1)'
/* SUB1: sees the same &HLQ */
PROC 0
GLOBAL &HLQ
WRITE SHARED HLQ IS &HLQ
PROC 0
GLOBAL &HLQ
SET &HLQ = USER1
EXEC 'USER1.CLIST(SUB1)'
/* SUB1: sees the same &HLQ */
PROC 0
GLOBAL &HLQ
WRITE SHARED HLQ IS &HLQ
SYSPROC and CLIST libraries
- SYSPROC is the ddname whose concatenated PDSs TSO searches for the %member form and for nested EXEC calls.
- Your logon procedure allocates the system CLIST libraries to SYSPROC automatically.
- Add your own library for the session with: ALLOC F(SYSPROC) DA('USER1.CLIST') SHR.
- After that, %PAYRPT JAN finds member PAYRPT in your PDS without any quoted dataset name.
- Keep production CLISTs in a shared team PDS allocated to SYSPROC by the logon proc, not by personal ALLOCs.
ALLOC F(SYSPROC) DA('USER1.CLIST') SHR
%PAYRPT JAN
EXEC 'USER1.CLIST(PAYRPT)' 'JAN' EXEC
%PAYRPT JAN
EXEC 'USER1.CLIST(PAYRPT)' 'JAN' EXEC
Calling CLISTs from REXX
- A REXX exec can run any CLIST through the TSO command environment with EXEC.
- ADDRESS TSO "EXEC 'USER1.CLIST(ARCHDSN)' 'USER1.DATA'" runs the CLIST and waits for it.
- After the call, the REXX special variable RC holds the CLIST's return code (from EXIT CODE(n)).
- CLISTs can also call REXX execs the same way, so mixed-language toolchains are common.
/* REXX exec that calls a CLIST */
ADDRESS TSO "EXEC 'USER1.CLIST(ARCHDSN)' 'USER1.DATA'"
IF RC = 0 THEN SAY "ARCHIVE OK"
ELSE SAY "ARCHIVE FAILED, RC =" RC
ADDRESS TSO "EXEC 'USER1.CLIST(ARCHDSN)' 'USER1.DATA'"
IF RC = 0 THEN SAY "ARCHIVE OK"
ELSE SAY "ARCHIVE FAILED, RC =" RC
Calling CLISTs from ISPF
- From any ISPF command line (including option 6), %ARCHDSN USER1.DATA runs the CLIST under ISPF.
- Inside a panel's )PROC section, SELECT CMD(%ARCHDSN USER1.DATA) runs the CLIST when the panel processes.
- A CLIST can call ISPF dialog services directly: ISPEXEC DISPLAY PANEL(MYPANEL) shows a panel, ISPEXEC VGET/VPUT move variables between the CLIST and the ISPF shared pool.
- ISPF services need an ISPF session: they fail if the CLIST runs in batch TMP without ISPF started.
/* inside a CLIST running under ISPF */
ISPEXEC VGET (CHOICE) SHARED
ISPEXEC DISPLAY PANEL(MYMENU)
ISPEXEC VPUT (CHOICE) SHARED
ISPEXEC VGET (CHOICE) SHARED
ISPEXEC DISPLAY PANEL(MYMENU)
ISPEXEC VPUT (CHOICE) SHARED
Complete utility CLIST: ARCHDSN
ARCHDSN archives a dataset by renaming it with a date stamp. It validates the input with &SYSDSN, builds YYMMDD from &SYSDATE with &SUBSTR, traps errors, and returns a meaningful code. Save it as member ARCHDSN and run %ARCHDSN USER1.DATA.
/* ARCHDSN: rename a dataset adding a DYYMMDD suffix */
/* usage: %ARCHDSN USER1.DATA */
PROC 1 DSN
CONTROL NOMSG
ERROR DO
WRITE *** ARCHIVE FAILED, LASTCC = &LASTCC
EXIT CODE(12)
END
IF &SYSDSN('&DSN') = OK THEN +
DO
/* &SYSDATE is MM/DD/YY: pull YY, MM, DD apart */
SET &YY = &SUBSTR(7:8:&SYSDATE)
SET &MM = &SUBSTR(1:2:&SYSDATE)
SET &DD = &SUBSTR(4:5:&SYSDATE)
SET &STAMP = D&YY&MM&DD
SET &NEW = &DSN.&STAMP
WRITE ARCHIVING &DSN TO &NEW
RENAME '&DSN' '&NEW'
IF &LASTCC = 0 THEN +
DO
WRITE ARCHIVE COMPLETED
EXIT CODE(0)
END
ELSE +
DO
WRITE RENAME FAILED, RC = &LASTCC
EXIT CODE(8)
END
END
ELSE +
DO
WRITE DATASET &DSN NOT FOUND - NOTHING ARCHIVED
EXIT CODE(4)
END
/* usage: %ARCHDSN USER1.DATA */
PROC 1 DSN
CONTROL NOMSG
ERROR DO
WRITE *** ARCHIVE FAILED, LASTCC = &LASTCC
EXIT CODE(12)
END
IF &SYSDSN('&DSN') = OK THEN +
DO
/* &SYSDATE is MM/DD/YY: pull YY, MM, DD apart */
SET &YY = &SUBSTR(7:8:&SYSDATE)
SET &MM = &SUBSTR(1:2:&SYSDATE)
SET &DD = &SUBSTR(4:5:&SYSDATE)
SET &STAMP = D&YY&MM&DD
SET &NEW = &DSN.&STAMP
WRITE ARCHIVING &DSN TO &NEW
RENAME '&DSN' '&NEW'
IF &LASTCC = 0 THEN +
DO
WRITE ARCHIVE COMPLETED
EXIT CODE(0)
END
ELSE +
DO
WRITE RENAME FAILED, RC = &LASTCC
EXIT CODE(8)
END
END
ELSE +
DO
WRITE DATASET &DSN NOT FOUND - NOTHING ARCHIVED
EXIT CODE(4)
END
