Anatomy of a batch report
Long before dashboards, the output of a batch job was paper: a stack of green-bar listings on someone's desk in the morning. Most of those reports are now PDFs or files that land in a document system, but the programs that make them are the same, and changing a report is one of the most common tickets a junior COBOL developer gets.
The parts of a report
BRANCH DEPOSIT LIST PAGE 1 <- page heading (title, page no.)
ACCOUNT NAME AMOUNT <- column headings
100200 JANE DOE 1,250.50 <- detail lines, one per record
300100 GRACE HOPPER 75.00-
TOTAL DEPOSITS 1,175.50 <- total line(s)
- Page heading: report title, run date, page number. Repeated on every page.
- Column headings: aligned over the columns below them.
- Detail lines: one per input record (or per group, in a summary report).
- Control totals: subtotals when a group ends (a control break) and grand totals at the end.
Print lines are templates
Each kind of line is a WORKING-STORAGE group. FILLER items with VALUE
hold spacing and literal text; named fields, often edited pictures,
receive the data. The column positions are simply the sum of the PIC
sizes before them:
IDENTIFICATION DIVISION.
PROGRAM-ID. RPTDEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 HDG-1.
05 FILLER PIC X(20) VALUE "BRANCH DEPOSIT LIST".
05 FILLER PIC X(6) VALUE SPACES.
05 FILLER PIC X(5) VALUE "PAGE ".
05 H1-PAGE PIC Z9.
01 HDG-2.
05 FILLER PIC X(8) VALUE "ACCOUNT".
05 FILLER PIC X(14) VALUE "NAME".
05 FILLER PIC X(10) VALUE " AMOUNT".
01 DETAIL-LINE.
05 DL-ACCT PIC X(6).
05 FILLER PIC X(2) VALUE SPACES.
05 DL-NAME PIC X(12).
05 FILLER PIC X(2) VALUE SPACES.
05 DL-AMOUNT PIC ZZZ,ZZ9.99-.
01 TOTAL-LINE.
05 FILLER PIC X(22) VALUE " TOTAL DEPOSITS".
05 TL-AMOUNT PIC ZZZ,ZZ9.99-.
01 WS-TOTAL PIC S9(6)V99 VALUE 0.
PROCEDURE DIVISION.
MOVE 1 TO H1-PAGE
DISPLAY HDG-1
DISPLAY HDG-2
MOVE "100200" TO DL-ACCT
MOVE "JANE DOE" TO DL-NAME
MOVE 1250.5 TO DL-AMOUNT
ADD 1250.5 TO WS-TOTAL
DISPLAY DETAIL-LINE
MOVE "300100" TO DL-ACCT
MOVE "GRACE HOPPER" TO DL-NAME
MOVE -75 TO DL-AMOUNT
ADD -75 TO WS-TOTAL
DISPLAY DETAIL-LINE
MOVE WS-TOTAL TO TL-AMOUNT
DISPLAY TOTAL-LINE
STOP RUN.
Output:
BRANCH DEPOSIT LIST PAGE 1
ACCOUNT NAME AMOUNT
100200 JANE DOE 1,250.50
300100 GRACE HOPPER 75.00-
TOTAL DEPOSITS 1,175.50
To put a line in a report file instead of on SYSOUT, write it:
WRITE RPT-LINE FROM DETAIL-LINE, where RPT-LINE is the FD record.
Printers, ASA and this course
On z/OS a print dataset is usually RECFM=FBA, LRECL=133: byte 1 is an
ASA carriage-control character (1 new page, blank single space,
0 double space) and the next 132 bytes are the line. You don't set that
byte yourself; you write
WRITE RPT-LINE FROM HDG-1 AFTER ADVANCING PAGE
WRITE RPT-LINE FROM DETAIL-LINE AFTER ADVANCING 1 LINE
and the compiler fills it in. In this course, reports are plain text
datasets so they can be compared line by line: use a plain WRITE for
every line (one record = one line), write a line of spaces where you want a
blank line, and mark new pages with the page heading itself.
Report Writer
COBOL also has a declarative Report Writer (RD entries, TYPE IS
PAGE HEADING, CONTROL FOOTING, GENERATE). It works, but most shops
never adopted it, so the reports you'll maintain are built procedurally,
exactly as in this module.
On the job
Before changing a report, get a copy of the current output and the spec, then count columns. The classic bug is a print line that grew by one byte: every field to the right shifts, and a downstream program that reads the report by position (yes, they exist) breaks.