COBOL report writing is the process of producing formatted output—usually for a printer or report file—with pagination, page headings, detail lines, and optional footings. You use a sequential output file, the WRITE statement with BEFORE or AFTER ADVANCING to control line and page spacing, and often the LINAGE clause so the runtime tracks the current line on the page. This page explains how to structure a simple report: headings, detail lines, and page breaks.
A report is like a letter that has a title at the top of each page, lots of lines of information in the middle, and maybe a line at the bottom (like "Page 2"). Report writing in COBOL is telling the computer: "First print the title, then print one line of data, then the next line, and when the page is full, go to a new page and print the title again." The WRITE statement says what to print and whether to move to the next line or the next page. LINAGE and LINAGE-COUNTER help the program know when the page is full.
Your report goes to a sequential file (OPEN OUTPUT report-file). For pagination you typically use the LINAGE clause in the FD. LINAGE IS n LINES defines the number of lines in the page body. Optionally you specify WITH FOOTING AT m (the line where the footing area starts), LINES AT TOP, and LINES AT BOTTOM for margins. The compiler creates LINAGE-COUNTER, which holds the current line number within the page (1 to n). As you WRITE with ADVANCING, the runtime updates LINAGE-COUNTER. When it reaches the end of the body (or the footing area, depending on implementation), you can trigger a page advance. See the Page Control tutorial for full LINAGE syntax.
The WRITE statement sends a record to the file. For report files you usually specify how the print position advances. AFTER ADVANCING 1 LINE means: advance the current position by one line (so the next line is blank or the next line down), then write the record. So each WRITE goes to a new line. BEFORE ADVANCING 1 LINE means: write the record at the current position, then advance one line. For normal detail lines, AFTER ADVANCING 1 LINE is common. To advance to a new page, use AFTER ADVANCING PAGE (position moves to the first line of the next page, then you write—good for a page heading) or BEFORE ADVANCING PAGE (write at current position, then eject—good for the last line before a page break). You can also use AFTER ADVANCING identifier LINES or integer LINES to skip multiple lines.
| Form | Effect | Typical use |
|---|---|---|
| AFTER ADVANCING 1 LINE | Advance one line, then write. | Normal detail lines; each WRITE on next line. |
| BEFORE ADVANCING 1 LINE | Write, then advance one line. | Same net effect as above; position after write is next line. |
| AFTER ADVANCING n LINES | Advance n lines (blank lines), then write. | Leave gaps or skip lines. |
| AFTER ADVANCING PAGE | Advance to next page, then write. | First line on new page (e.g. heading). |
| BEFORE ADVANCING PAGE | Write, then advance to next page. | Last line on current page, then eject. |
123456789101112131415161701 REPORT-LINE PIC X(132). 01 HEADING-LINE PIC X(132) VALUE 'CUSTOMER REPORT PAGE 1'. *> First page heading WRITE REPORT-LINE FROM HEADING-LINE AFTER ADVANCING PAGE *> Detail lines PERFORM UNTIL NO-MORE-RECORDS *> Build REPORT-LINE from data WRITE REPORT-LINE AFTER ADVANCING 1 LINE IF LINAGE-COUNTER >= 55 WRITE REPORT-LINE BEFORE ADVANCING PAGE WRITE REPORT-LINE FROM HEADING-LINE AFTER ADVANCING PAGE END-IF READ INFILE ... END-PERFORM.
In the snippet, the first WRITE prints the heading at the top of page 1. The loop writes each detail line with AFTER ADVANCING 1 LINE. When LINAGE-COUNTER reaches 55 (or your chosen limit), you write the last line and advance page, then write the heading on the new page. Exact handling of LINAGE-COUNTER (e.g. when it is incremented, when it resets) depends on the compiler; check your manual.
A page heading is one or more lines you print at the top of each page (e.g. report title, column headers, date, page number). You typically write the heading right after advancing to a new page: WRITE HEADING-LINE AFTER ADVANCING PAGE (and possibly more lines with AFTER ADVANCING 1 LINE). Keep the heading in working storage and update the page number (and date if needed) before each new page. A footing is one or more lines at the bottom (e.g. "Page n of m", confidentiality notice). You can write the footing when you detect that you are about to leave the page (e.g. when LINAGE-COUNTER reaches the footing area) or in a controlled way before BEFORE ADVANCING PAGE. Some implementations trigger AT END-OF-PAGE when writing would go into the footing area; in that case you can use AT END-OF-PAGE to write the footing and then advance.
A simple report flow: (1) OPEN the report file and the input file(s). (2) Write the first page heading (e.g. AFTER ADVANCING PAGE so you start at line 1 of page 1). (3) Read input and for each record build a detail line and WRITE it AFTER ADVANCING 1 LINE. (4) Before or after each write, check LINAGE-COUNTER (or equivalent). When you have used enough lines (e.g. 55), write any footing line if needed, then WRITE ... BEFORE ADVANCING PAGE to eject. Then write the page heading for the new page (AFTER ADVANCING PAGE). (5) Repeat until all input is processed. (6) CLOSE files. This keeps headings on every page and avoids overprinting the page body.
The record you WRITE (e.g. REPORT-LINE) is usually a fixed-length field (e.g. PIC X(132) for 132-column print). You build the line by moving data into it with proper spacing and edited fields (e.g. MOVE SPACES TO REPORT-LINE, then MOVE customer-name TO REPORT-LINE(1:30), MOVE amount to REPORT-LINE(40:12) with editing). Use reference modification or a detailed layout (group items with correct positions) so columns align. For column headers, use a literal or a header line that matches the positions of the detail data.
1. To print each detail line on the next line you use:
2. LINAGE-COUNTER is used to:
3. To start a new page and then print a heading you typically: