Feeding a program with SYSIN and PARM
You met ACCEPT in the first module. Now you can see where its input
comes from on a mainframe: the step's SYSIN DD. There's a second,
smaller channel too: the PARM on the EXEC statement.
Instream data: DD *
//STATS EXEC PGM=BRSTATS,PARM='DUB1'
//ACCTIN DD DSN=BANK.ACCOUNTS,DISP=SHR
//SYSOUT DD SYSOUT=*
//SYSIN DD *
20260924
/*
DD * means "the data follows in the JCL". Every line up to the /*
delimiter (or the next // statement) is an 80-byte record. Each
ACCEPT reads the next one:
IDENTIFICATION DIVISION.
PROGRAM-ID. RUNDATE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-RUN-DATE PIC X(8).
01 WS-MODE PIC X(4).
PROCEDURE DIVISION.
ACCEPT WS-RUN-DATE
ACCEPT WS-MODE
DISPLAY "RUN DATE " WS-RUN-DATE " MODE " WS-MODE
STOP RUN.
With 20260924 and FULL as the two instream lines, it displays
RUN DATE 20260924 MODE FULL. Put instream data in column 1: an
ACCEPT into PIC X(8) takes the first eight positions of the record,
so a leading blank shifts everything.
SYSIN is used for small control data: the business date, a
"full or incremental" switch, a list of branches to process. The same
program runs every night; only the cards change. Utilities read their
instructions from SYSIN too, as you'll see with DFSORT.
PARM: a short string on the EXEC
//STATS EXEC PGM=BRSTATS,PARM='DUB1'
PARM passes up to 100 characters to the program. Quote it if it
contains commas or special characters: PARM='DUB1,FULL'. In GnuCOBOL,
you read it with ACCEPT ... FROM COMMAND-LINE:
IDENTIFICATION DIVISION.
PROGRAM-ID. SHOWPARM.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-PARM PIC X(20).
PROCEDURE DIVISION.
ACCEPT WS-PARM FROM COMMAND-LINE
DISPLAY "PARM IS " WS-PARM
STOP RUN.
PARM in IBM Enterprise COBOL
On z/OS the main program receives PARM through its LINKAGE
SECTION: a halfword binary length followed by the text, named on
PROCEDURE DIVISION USING:
LINKAGE SECTION.
01 LS-PARM.
05 LS-PARM-LEN PIC S9(4) COMP.
05 LS-PARM-TEXT PIC X(100).
PROCEDURE DIVISION USING LS-PARM.
Only the first LS-PARM-LEN characters are valid. The idea is the
same: a short value from the JCL, read once at the start.
Talking back: RETURN-CODE
Input flows into the program through SYSIN and PARM. The program
talks back to the job through its return code. Move a number to the
special register RETURN-CODE before STOP RUN, and it becomes the
step's condition code in the job log:
IF WS-COUNT = 0
MOVE 4 TO RETURN-CODE
END-IF
STOP RUN.
IEF142I BRJOB STATS - STEP WAS EXECUTED - COND CODE 0004
The convention across IBM utilities and most shops:
| RC | Meaning |
|---|---|
| 0 | Everything worked |
| 4 | Warning: finished, but look at this (empty input, a few rejects) |
| 8 | Error: output is incomplete or wrong |
| 12, 16 | Severe: couldn't run at all (bad control cards, missing input) |
The next lesson uses these codes to decide which later steps run.
On the job
The business date usually arrives through SYSIN, often from a
one-record control dataset shared by the whole night's schedule
rather than typed into each job. When a job has to be rerun for last
Tuesday, operations change that one card, not your program.
Your task
Write BRSTATS, a branch statistics program that operations run
with this JCL:
//STATS EXEC PGM=BRSTATS,PARM='DUB1'
//ACCTIN DD DSN=BANK.ACCOUNTS,DISP=SHR
//SYSOUT DD SYSOUT=*
//SYSIN DD *
20260924
/*
- The branch code comes from
PARM. Read it withACCEPT WS-BRANCH FROM COMMAND-LINE. - The run date is the first
SYSINline. Read it with a plainACCEPT WS-RUN-DATE. - DD
ACCTINis the account file (already declared in the starter):
| Field | Picture | Positions |
|---|---|---|
ACCT-NO |
X(8) |
1–8 |
ACCT-BRANCH |
X(4) |
9–12 |
ACCT-NAME |
X(20) |
13–32 |
ACCT-BALANCE |
S9(7)V99 SIGN IS LEADING SEPARATE |
33–42 |
Count the accounts of that branch and total their balances, then display:
BRSTATS 20260924 BRANCH DUB1
ACCOUNTS: 00003
BALANCE: 14950.75
If the branch has no accounts, still display the three lines, but end with return code 4 so the job log flags it.