24 min read

Report generation is one of the most common tasks in business computing. Financial statements, audit reports, inventory listings, payroll summaries, management dashboards -- virtually every business application produces printed or formatted output...

Chapter 15: Report Writer Module

Introduction

Report generation is one of the most common tasks in business computing. Financial statements, audit reports, inventory listings, payroll summaries, management dashboards -- virtually every business application produces printed or formatted output. In traditional COBOL programming, generating these reports requires substantial procedural code: tracking line counts for page breaks, detecting control breaks when group values change, accumulating subtotals at multiple levels, formatting headers and footers, and managing the complex interplay between all of these tasks.

The COBOL Report Writer module was designed to automate these mechanics. Rather than writing hundreds of lines of procedural code to manage report layout, page overflow, control breaks, and subtotal accumulation, Report Writer allows the programmer to declare what the report should look like, and the runtime system handles the how. This declarative approach can reduce report-generation code by 60 to 80 percent compared to manual coding.

Report Writer was part of the original COBOL standard and has been refined through successive standards (COBOL-68, COBOL-74, COBOL-85, and COBOL 2002). Although it has fallen out of favor in some shops -- partly due to historical compiler limitations and partly due to the rise of external report tools -- it remains a powerful feature supported by IBM Enterprise COBOL and GnuCOBOL. Understanding Report Writer is essential for maintaining legacy systems and for situations where its declarative approach offers clear advantages.

In this chapter, you will learn how to define reports using the REPORT SECTION of the DATA DIVISION, control page layout, implement automatic control breaks with subtotals, and drive report production using just three PROCEDURE DIVISION verbs: INITIATE, GENERATE, and TERMINATE.


15.1 Report Writer Overview

What Report Writer Automates

When you write a report manually (as we will see in Example 06), you must handle all of the following yourself:

  1. Page overflow detection: Counting lines and determining when to eject to a new page.
  2. Page heading and footing printing: Writing header lines at the top of each page and footer lines at the bottom.
  3. Control break detection: Comparing the current record's group fields against the previous record's values.
  4. Control heading and footing printing: Printing group headers when a new group starts and group footers when a group ends.
  5. Subtotal accumulation: Adding amounts into accumulators at each control level.
  6. Subtotal reset: Zeroing accumulators after printing subtotals.
  7. Grand total rollup: Summing subtotals from minor levels into major levels.
  8. Report heading and footing: Printing the first page title and the final report summary.
  9. Line spacing: Managing blank lines between groups and sections.

Report Writer automates all of these tasks. You describe the report layout in the REPORT SECTION, and the runtime handles the mechanics.

The Report Writer Architecture

Report Writer introduces several language elements:

Element Location Purpose
RD entry REPORT SECTION (DATA DIVISION) Defines report-level properties: page layout, control fields
Report group entries Under each RD Defines the visual structure: headings, details, footings
INITIATE PROCEDURE DIVISION Activates the report, triggers Report Heading
GENERATE PROCEDURE DIVISION Produces detail lines and triggers control break processing
TERMINATE PROCEDURE DIVISION Deactivates the report, triggers Report Footing
USE BEFORE REPORTING DECLARATIVES Allows custom logic before a report group is presented
PAGE-COUNTER Special register Automatically incremented page counter
LINE-COUNTER Special register Tracks current line position on the page

How a Report Writer Program is Structured

A Report Writer program follows this general pattern:

ENVIRONMENT DIVISION.
    FILE-CONTROL.
        SELECT input-file ...
        SELECT report-file ...    (the output print file)

DATA DIVISION.
    FILE SECTION.
        FD input-file ...
        FD report-file ...        (simple record definition)

    REPORT SECTION.
        RD report-name ...        (page layout, control fields)
            01 TYPE IS REPORT HEADING ...
            01 TYPE IS PAGE HEADING ...
            01 TYPE IS CONTROL HEADING ...
            01 detail-name TYPE IS DETAIL ...
            01 TYPE IS CONTROL FOOTING ...
            01 TYPE IS PAGE FOOTING ...
            01 TYPE IS REPORT FOOTING ...

PROCEDURE DIVISION.
    OPEN files
    INITIATE report-name
    READ input-file
    PERFORM UNTIL end-of-file
        GENERATE detail-name
        READ input-file
    END-PERFORM
    TERMINATE report-name
    CLOSE files

The PROCEDURE DIVISION is remarkably simple: just INITIATE, GENERATE in a loop, and TERMINATE. All the complex report logic is handled declaratively.


15.2 The REPORT SECTION and RD Entry

REPORT SECTION

The REPORT SECTION is a section within the DATA DIVISION, coded after the FILE SECTION and WORKING-STORAGE SECTION (or wherever local data is defined). It contains one or more RD (Report Description) entries, each describing a separate report.

       DATA DIVISION.
       FILE SECTION.
       FD  REPORT-FILE ...
       01  REPORT-RECORD              PIC X(133).

       REPORT SECTION.
       RD  EMPLOYEE-LISTING-REPORT ...

The FD for the report file needs only a simple record definition. Report Writer manages the actual record content; you never WRITE to the report file directly.

The RD Entry

The RD entry defines report-level properties:

       RD  report-name
           CONTROL IS control-field-list
           PAGE LIMIT IS integer LINES
           HEADING integer
           FIRST DETAIL integer
           LAST DETAIL integer
           FOOTING integer.

PAGE LIMIT Clause

PAGE LIMIT IS n LINES specifies the total number of lines on each page. For standard mainframe printing:

  • Standard fan-fold paper: 66 lines per page (11 inches at 6 lines per inch)
  • Condensed printing: 88 lines per page (11 inches at 8 lines per inch)
  • Letter-size reports: 60 lines per page (10 inches at 6 lines per inch)

Page Layout Sub-clauses

The sub-clauses of PAGE LIMIT define zones on the page:

Line 1  +---------------------------------+  <-- HEADING (line 1)
        |      Page Heading Area          |
        +---------------------------------+
Line 9  |      First Detail Position      |  <-- FIRST DETAIL (line 9)
        |                                 |
        |      Detail and Control         |
        |      Heading Area               |
        |                                 |
Line 55 |      Last Detail Position       |  <-- LAST DETAIL (line 55)
        +---------------------------------+
        |      Control Footing Area       |
Line 58 |      Footing Position           |  <-- FOOTING (line 58)
        +---------------------------------+
        |      Page Footing Area          |
Line 66 +---------------------------------+  <-- PAGE LIMIT (line 66)

The zones serve these purposes:

Zone Lines Contains
Heading area HEADING to FIRST DETAIL - 1 Page Heading (PH), Report Heading (RH)
Body area FIRST DETAIL to LAST DETAIL Detail (DE) lines, Control Headings (CH)
Footing area LAST DETAIL + 1 to FOOTING Control Footings (CF)
Page footing area FOOTING + 1 to PAGE LIMIT Page Footing (PF), Report Footing (RF)

When a detail line would exceed LAST DETAIL, Report Writer automatically ejects to a new page, prints the page footing and the next page heading, then continues with the detail line.

CONTROL IS Clause

The CONTROL IS clause lists the data fields that define control break levels, from major to minor:

       RD  PAYROLL-REPORT
           CONTROL IS FINAL
                      PR-REGION
                      PR-BRANCH
                      PR-DEPARTMENT
  • FINAL is the highest level. Its control footing prints once at the end of the report (grand totals).
  • Fields are listed from major (outermost) to minor (innermost).
  • The input file must be sorted on these fields in the order listed.
  • When a control field changes value, Report Writer automatically generates the appropriate control footings (from minor to major) and control headings (from major to minor).

15.3 Report Groups and Their Types

Report groups are 01-level entries under the RD that define the visual structure of the report. Each group has a TYPE IS clause that specifies when it is presented.

TYPE IS REPORT HEADING (RH)

Printed once when INITIATE is executed. Used for the report title page.

       01  TYPE IS REPORT HEADING.
           05  LINE 1.
               10  COLUMN 1            PIC X(133) VALUE ALL '='.
           05  LINE 2.
               10  COLUMN 45           PIC X(45)
                   VALUE 'EMPLOYEE MASTER LISTING'.
           05  LINE 3.
               10  COLUMN 1            PIC X(133) VALUE ALL '='.

TYPE IS PAGE HEADING (PH)

Printed at the top of every page. Typically contains column headings and the page number.

       01  TYPE IS PAGE HEADING.
           05  LINE 5.
               10  COLUMN 1            PIC X(10) VALUE 'EMP ID'.
               10  COLUMN 12           PIC X(20) VALUE 'LAST NAME'.
               10  COLUMN 55           PIC X(06) VALUE 'PAGE: '.
               10  COLUMN 61           PIC ZZZ9
                   SOURCE PAGE-COUNTER.

TYPE IS CONTROL HEADING (CH)

Printed when a new group starts for the specified control field. There can be one control heading for each field in the CONTROL IS list.

       01  DEPT-HEADER
           TYPE IS CONTROL HEADING SR-DEPARTMENT.
           05  LINE PLUS 2.
               10  COLUMN 1            PIC X(15)
                   VALUE 'DEPARTMENT:'.
               10  COLUMN 17           PIC X(04)
                   SOURCE SR-DEPARTMENT.

TYPE IS DETAIL (DE)

Printed for each GENERATE statement. This is the line that represents one input record. A report can have multiple detail group definitions, and you specify which one to generate.

       01  SALES-DETAIL
           TYPE IS DETAIL.
           05  LINE PLUS 1.
               10  COLUMN 1            PIC X(04)
                   SOURCE SR-DEPARTMENT.
               10  COLUMN 60           PIC $$$,$$$,MATH1MATH2$,$$9.99
                   SUM DL-SALE-AMT.
```

### TYPE IS PAGE FOOTING (PF)

Printed at the bottom of every page. Typically contains the page number and confidentiality notices.

```cobol
       01  TYPE IS PAGE FOOTING.
           05  LINE 59.
               10  COLUMN 1            PIC X(25)
                   VALUE 'SALES REPORT'.
               10  COLUMN 55           PIC X(06) VALUE 'PAGE: '.
               10  COLUMN 61           PIC ZZZ9
                   SOURCE PAGE-COUNTER.
```

### TYPE IS REPORT FOOTING (RF)

Printed once when `TERMINATE` is executed. Used for the final summary or sign-off section.

```cobol
       01  TYPE IS REPORT FOOTING.
           05  LINE PLUS 2.
               10  COLUMN 40           PIC X(55)
                   VALUE '*** END OF SALES REPORT ***'.
```

### Presentation Order

Report Writer presents groups in a specific order during processing:

1. **INITIATE**: Report Heading (RH) is printed.
2. **First GENERATE**: Page Heading (PH), then all applicable Control Headings (CH) from major to minor, then the Detail line (DE).
3. **Subsequent GENERATE** (no control break): Detail line only.
4. **GENERATE with control break**: Control Footings (CF) from minor to major for the group that ended, then Control Headings (CH) from major to minor for the new group, then the Detail line.
5. **Page overflow**: Page Footing (PF), new page, Page Heading (PH), then continue.
6. **TERMINATE**: All remaining Control Footings (CF) from minor to FINAL, then Report Footing (RF).

---

## 15.4 LINE and COLUMN Clauses

### LINE Clause

The LINE clause specifies the vertical position of a report item.

**Absolute positioning** uses a line number:
```cobol
           05  LINE 5.     *> Always prints on line 5 of the page
```

**Relative positioning** uses LINE PLUS:
```cobol
           05  LINE PLUS 1.    *> One line after the previous line
           05  LINE PLUS 2.    *> Skip a blank line
```

Absolute LINE numbers are typically used in page headings and page footings, where items must appear at fixed positions. Relative positioning is used in detail lines and control headings/footings, where the position depends on preceding output.

### COLUMN Clause

The COLUMN clause specifies the horizontal position (character column) where an item begins:

```cobol
               10  COLUMN 1     PIC X(10) VALUE 'EMP ID'.
               10  COLUMN 12    PIC X(20) VALUE 'LAST NAME'.
               10  COLUMN 56    PIC ZZZ,ZZ9.99 SOURCE EMP-SALARY.
```

Column numbers start at 1. Items on the same LINE can be placed at any column positions; they do not need to be contiguous.

---

## 15.5 SOURCE, VALUE, and SUM Clauses

### SOURCE Clause

The SOURCE clause specifies where the data for a report item comes from:

```cobol
               10  COLUMN 1    PIC X(06)
                   SOURCE EMP-ID.
```

The source can be any data item accessible in the program: input record fields, WORKING-STORAGE fields, or calculated values. The SOURCE value is moved to the report item at the time the group is presented.

### VALUE Clause

The VALUE clause provides a literal value for the report item:

```cobol
               10  COLUMN 1    PIC X(20)
                   VALUE 'DEPARTMENT TOTAL:'.
```

This is typically used for labels, headings, and separator lines.

### SUM Clause

The SUM clause is one of Report Writer's most powerful features. It provides **automatic accumulation** of numeric values.

```cobol
      * In the DETAIL line:
               10  COLUMN 60  DL-SALE-AMT
                                       PIC $$$,$$$,$$9.99
                   SOURCE SR-SALE-AMOUNT.

      * In the CONTROL FOOTING:
               10  COLUMN 60  CF-DEPT-TOTAL
                                       PIC $$$$,$$$,$$9.99
                   SUM DL-SALE-AMT.

How SUM works:

  1. Each time a DETAIL line is generated, the value of DL-SALE-AMT is automatically added to CF-DEPT-TOTAL.
  2. When the control footing is presented (at a control break), CF-DEPT-TOTAL contains the accumulated sum.
  3. After the control footing is presented, CF-DEPT-TOTAL is automatically reset to zero.

SUM of SUM (Rollup)

At higher control levels, you can SUM a lower-level SUM field. This creates a rollup chain:

      * Department footing:
               10  CF-DEPT-TOTAL       PIC $$$$,$$$,$$9.99
                   SUM DL-SALE-AMT.

      * Final footing:
               10  CF-GRAND-TOTAL      PIC $$$$,$$$,$$9.99
                   SUM CF-DEPT-TOTAL.

Each time a department footing is presented, CF-DEPT-TOTAL is added to CF-GRAND-TOTAL before being reset. This way, the grand total accumulates from the department totals, which in turn accumulated from the detail values.

RESET ON Clause

By default, a SUM field in a control footing is reset to zero after the control footing is presented. The RESET ON clause overrides this behavior:

               10  CF-RUNNING-TOTAL    PIC $$$$,$$$,$$9.99
                   SUM DL-AMOUNT
                   RESET ON FINAL.

RESET ON FINAL means the field is never reset during the report -- it accumulates from the first record to the last. This is useful for running totals.

You can specify any higher control level in RESET ON to control when the accumulator clears:

      * In a branch-level control footing:
               10  CF-REGION-RUNNING   PIC $$$$,$$$,$$9.99
                   SUM DL-AMOUNT
                   RESET ON region-field.

This field accumulates across branches but resets when the region changes.


15.6 GROUP INDICATE and NEXT GROUP

GROUP INDICATE

The GROUP INDICATE clause causes a report item to be printed only on the first detail line of a control group. On subsequent detail lines within the same group, the item is suppressed (replaced with spaces).

       01  PAYROLL-DETAIL TYPE IS DETAIL.
           05  LINE PLUS 1.
               10  COLUMN 1            PIC X(04)
                   SOURCE PR-REGION
                   GROUP INDICATE.
               10  COLUMN 8            PIC X(06)
                   SOURCE PR-BRANCH
                   GROUP INDICATE.
               10  COLUMN 22           PIC X(06)
                   SOURCE PR-EMPLOYEE-ID.

This produces clean output where the region and branch codes appear only once per group, rather than being repeated on every line:

EAST  BR0001  E10001  ADAMS, JOHN          $55,000.00
              E10002  BAKER, SUSAN          $48,000.00
      BR0002  E20001  EVANS, ROBERT        $78,000.00
              E20002  FORD, JENNIFER        $65,000.00
CENT  BR0003  E30001  HARRIS, PATRICIA     $51,000.00

NEXT GROUP Clause

The NEXT GROUP clause specifies spacing after a report group:

       01  DEPT-FOOTER
           TYPE IS CONTROL FOOTING SR-DEPARTMENT
           NEXT GROUP PLUS 1.
  • NEXT GROUP PLUS n inserts n blank lines after this group.
  • NEXT GROUP NEXT PAGE forces a page break after this group.
  • NEXT GROUP integer positions the next group at the specified absolute line number.

15.7 PROCEDURE DIVISION Verbs

INITIATE

           INITIATE report-name

The INITIATE statement activates a report. It: - Sets PAGE-COUNTER to 1 - Sets LINE-COUNTER to 0 - Initializes all SUM counters to zero - Presents the Report Heading (RH) if one is defined - Presents the first Page Heading (PH)

You must OPEN the report file before executing INITIATE. Do not WRITE to the report file yourself; Report Writer manages all output.

GENERATE

           GENERATE detail-name

The GENERATE statement is the workhorse of Report Writer. It: 1. Saves the current values of all control fields. 2. Compares them against the previous values. 3. If a control break is detected: a. Presents Control Footings from minor to major for each changed level. b. Presents Control Headings from major to minor for the new group. 4. Checks if the detail line will fit on the current page. 5. If page overflow: a. Presents the Page Footing. b. Advances to a new page. c. Presents the Page Heading. 6. Presents the Detail line. 7. Adds SOURCE values to SUM accumulators.

Summary Reporting

You can also generate at the report level:

           GENERATE report-name

This performs control break processing and accumulation but does not print the detail line. Only control headings, control footings, and page headings/footings are presented. This is useful for summary reports that show only subtotals without individual detail lines.

TERMINATE

           TERMINATE report-name

The TERMINATE statement finalizes a report. It: 1. Presents all remaining Control Footings from minor to FINAL. 2. Presents the Report Footing (RF) if one is defined. 3. Deactivates the report.

You must CLOSE the report file after executing TERMINATE.

Complete Processing Loop

           OPEN INPUT  INPUT-FILE
           OPEN OUTPUT REPORT-FILE

           INITIATE SALES-REPORT

           READ INPUT-FILE
               AT END SET END-OF-FILE TO TRUE
           END-READ

           PERFORM UNTIL END-OF-FILE
               GENERATE SALES-DETAIL
               READ INPUT-FILE
                   AT END SET END-OF-FILE TO TRUE
               END-READ
           END-PERFORM

           TERMINATE SALES-REPORT

           CLOSE INPUT-FILE
           CLOSE REPORT-FILE

15.8 USE BEFORE REPORTING Declarative

The USE BEFORE REPORTING declarative allows you to execute procedural code just before a specific report group is presented. This is coded in the DECLARATIVES section of the PROCEDURE DIVISION.

       PROCEDURE DIVISION.
       DECLARATIVES.

       DEPT-CF-SECTION SECTION.
           USE BEFORE REPORTING DEPT-FOOTER.
       DEPT-CF-PROC.
           MOVE WS-DEPT-COUNT TO CF-DEPT-COUNT
           MOVE ZERO TO WS-DEPT-COUNT
           .

       END DECLARATIVES.

Common uses of USE BEFORE REPORTING:

  • Populating non-SUM fields in control footings (like record counts or calculated averages).
  • Looking up descriptions before control headings are presented.
  • Performing calculations that depend on accumulated values.
  • Conditionally suppressing a report group by moving spaces to its fields.

Important rules: - The declarative executes before the group is presented. - You can reference and modify report group data items within the declarative. - Each USE BEFORE REPORTING must be in its own section within DECLARATIVES. - Do not execute INITIATE, GENERATE, or TERMINATE within a declarative.


15.9 Special Registers

PAGE-COUNTER

PAGE-COUNTER is automatically maintained by Report Writer. It is set to 1 by INITIATE and incremented each time a new page begins. You can reference it in SOURCE clauses:

               10  COLUMN 61           PIC ZZZ9
                   SOURCE PAGE-COUNTER.

You can also modify it procedurally if needed (for example, to restart numbering after a section break).

LINE-COUNTER

LINE-COUNTER tracks the current line position on the page. It is set to 0 by INITIATE and updated each time a report line is presented. You can reference it but should rarely need to modify it.


15.10 Multi-Level Control Breaks

Report Writer excels at handling multi-level control breaks, which are among the most complex patterns in report programming.

How Multi-Level Breaks Work

Consider a report with three control levels: Region, Branch, and Department. The input file must be sorted by Region, Branch within Region, and Department within Branch.

When the Branch field changes: 1. Department control footing is presented (for the last department in the old branch). 2. Branch control footing is presented. 3. Branch control heading is presented (for the new branch). 4. Department control heading is presented (for the first department in the new branch).

When the Region field changes: 1. Department control footing is presented. 2. Branch control footing is presented. 3. Region control footing is presented. 4. Region control heading is presented (for the new region). 5. Branch control heading is presented. 6. Department control heading is presented.

All of this happens automatically with a single GENERATE statement. In manual coding, you would need nested IF statements to detect each level of break and manage the cascade of footings and headings.

SUM Rollup Across Levels

With multi-level breaks, the SUM clause creates a rollup chain:

Detail:      DL-SALARY   (individual employee salary)
                 |
                 v (SUM DL-SALARY)
Dept CF:     CF-DEPT-SAL  (department total)
                 |
                 v (SUM CF-DEPT-SAL)
Branch CF:   CF-BRANCH-SAL (branch total)
                 |
                 v (SUM CF-BRANCH-SAL)
Region CF:   CF-REGION-SAL (region total)
                 |
                 v (SUM CF-REGION-SAL)
Final CF:    CF-GRAND-SAL  (grand total)

Each level's SUM value is added to the next higher level before being reset. This ensures that grand totals are the sum of region totals, which are the sum of branch totals, which are the sum of department totals.

See Example 05 (example-05-multi-level.cob) for a complete three-level control break program demonstrating this pattern.


15.11 Report Writer vs. Manual Report Coding

Code Volume Comparison

The following table compares the key areas of a control-break report program:

Task Manual Coding Report Writer
Page heading definition WORKING-STORAGE record (10-15 lines) PAGE HEADING group (5-10 lines)
Detail line definition WORKING-STORAGE record (10-15 lines) DETAIL group (5-10 lines)
Control footing definition WORKING-STORAGE record + accumulator fields (15-20 lines) CF group with SUM (8-12 lines)
Page overflow detection IF statement + line counter (5-10 lines) Automatic (0 lines)
Control break detection Nested IF/EVALUATE (10-30 lines per level) Automatic (0 lines)
Subtotal accumulation ADD statements (2-5 lines per field per level) SUM clause (1 line per field)
Subtotal reset MOVE ZERO statements (1-3 lines per level) Automatic (0 lines)
Page heading printing WRITE + AFTER ADVANCING (3-5 lines) Automatic (0 lines)
Page footing printing WRITE statements (3-5 lines) Automatic (0 lines)
Main processing loop 30-80 lines 3-5 lines

For a three-level control break report, a manual implementation might require 400-600 lines of procedural code. The same report with Report Writer might need 200-300 lines of REPORT SECTION definitions and 20-30 lines of procedural code.

Examples 02 and 06 Comparison

Examples 02 and 06 in this chapter produce the same report from the same input data. Example 02 uses Report Writer; Example 06 uses manual coding. Compare the PROCEDURE DIVISION:

Report Writer (Example 02):

       2000-PROCESS-SALES.
           COMPUTE WS-COMMISSION-AMT =
               SR-SALE-AMOUNT * SR-COMMISSION-PCT
           ADD 1 TO WS-RECORD-COUNT
           GENERATE SALES-DETAIL
           PERFORM 8000-READ-SALES
           .

Manual Coding (Example 06):

       2000-PROCESS-SALES.
           IF FIRST-RECORD
               MOVE SR-DEPARTMENT TO WS-PREV-DEPARTMENT
               MOVE SR-DEPT-NAME  TO WS-PREV-DEPT-NAME
               SET NOT-FIRST-RECORD TO TRUE
               PERFORM 4200-PRINT-DEPT-HEADER
           ELSE
               IF SR-DEPARTMENT NOT = WS-PREV-DEPARTMENT
                   PERFORM 4400-PRINT-DEPT-FOOTER
                   IF WS-LINE-COUNT + 5 > WS-LINES-PER-PAGE
                       PERFORM 4500-PRINT-PAGE-FOOTER
                       PERFORM 4100-PRINT-PAGE-HEADING
                   END-IF
                   MOVE SR-DEPARTMENT TO WS-PREV-DEPARTMENT
                   MOVE SR-DEPT-NAME  TO WS-PREV-DEPT-NAME
                   PERFORM 4200-PRINT-DEPT-HEADER
               END-IF
           END-IF
           COMPUTE WS-COMMISSION-AMT =
               SR-SALE-AMOUNT * SR-COMMISSION-PCT
           IF WS-LINE-COUNT >= WS-LINES-PER-PAGE
               PERFORM 4500-PRINT-PAGE-FOOTER
               PERFORM 4100-PRINT-PAGE-HEADING
           END-IF
           PERFORM 4300-PRINT-DETAIL-LINE
           ADD SR-SALE-AMOUNT  TO WS-DEPT-SALE-TOTAL
           ADD WS-COMMISSION-AMT TO WS-DEPT-COMM-TOTAL
           ADD 1 TO WS-DEPT-RECORD-COUNT
           ADD SR-SALE-AMOUNT  TO WS-GRAND-SALE-TOTAL
           ADD WS-COMMISSION-AMT TO WS-GRAND-COMM-TOTAL
           ADD 1 TO WS-GRAND-RECORD-COUNT
           PERFORM 8000-READ-SALES
           .

The manual version requires an additional seven paragraphs (4000 through 4700) for printing headings, details, footings, and managing page overflow.

When to Use Report Writer

Use Report Writer when: - The report has control breaks with subtotals at one or more levels. - Page layout and overflow handling are important. - The report format is well-defined and relatively static. - Reduced maintenance effort is a priority. - The report is a standard listing, summary, or financial statement.

Use manual coding when: - The report requires highly dynamic layout (e.g., variable column positions). - Output goes to a non-print destination (database, API, web service). - The compiler does not support Report Writer. - The report requires complex conditional formatting that exceeds Report Writer capabilities. - Team expertise with Report Writer is limited and training is impractical.


15.12 Page Overflow Handling

Report Writer manages page overflow automatically, but understanding the mechanism is important for designing reports that look correct across page boundaries.

The Overflow Detection Mechanism

Before presenting a detail line or control heading, Report Writer checks whether the line will fit within the body area (between FIRST DETAIL and LAST DETAIL). If it will not fit:

  1. The Page Footing (PF) is presented.
  2. A new page begins.
  3. PAGE-COUNTER is incremented.
  4. The Page Heading (PH) is presented.
  5. Processing continues with the line that triggered the overflow.

Control Footings Near Page Bottom

When a control break occurs near the bottom of a page, Report Writer must present the control footing. Control footings can appear between LAST DETAIL + 1 and the FOOTING line number. If the control footing would exceed the FOOTING area, a page break occurs first.

This is why the FOOTING value should be set several lines below LAST DETAIL: to leave room for control footings to print on the same page as their associated detail lines.

Designing for Page Breaks

Best practices:

  1. Leave adequate footing space: Set FOOTING at least 5-6 lines below LAST DETAIL to accommodate multi-line control footings.
  2. Keep control headings compact: A 3-line control heading is less likely to cause awkward page breaks than a 7-line heading.
  3. Use NEXT GROUP NEXT PAGE for major section breaks if each section should start on a new page.
  4. Test with varying data volumes to ensure page breaks fall in reasonable places.

15.13 Print Control Characters

ASA Control Characters

On IBM mainframes, the first character of each print line is typically an ASA (American Standards Association) control character that directs the printer:

Character Action
(space) Single space before printing
0 Double space before printing
- Triple space before printing
+ No advance (overprint)
1 Skip to channel 1 (top of page)

When the report file is defined with RECFM=FBA in JCL, the first byte of each 133-character record is the ASA control character. Report Writer generates these characters automatically based on LINE and PAGE positioning.

DCB Attributes in JCL

For a standard report file:

//RPTFILE  DD SYSOUT=*,DCB=(RECFM=FBA,LRECL=133,BLKSIZE=1330)
  • RECFM=FBA: Fixed-length, blocked, ASA control characters.
  • LRECL=133: 132 print positions + 1 ASA control character.
  • BLKSIZE=1330: Block size (10 records per block).

Machine Control Characters

Some installations use machine control characters instead of ASA. These are specified with RECFM=FBM. Machine control characters use different byte values and are specific to the printer hardware. ASA is far more common in modern practice.


15.14 IBM Enterprise COBOL Support

IBM Enterprise COBOL for z/OS (currently Version 6.4) fully supports the Report Writer module. Key considerations:

  1. Compiler option: Report Writer is included in the standard compiler; no special options are needed.
  2. REPORT clause on FD: The FD for the report file can include REPORT IS report-name, linking the file to the RD entry. However, this is optional in IBM Enterprise COBOL.
  3. Multiple reports: A single file can be associated with multiple RD entries.
  4. Performance: Report Writer generates inline code similar to what a programmer would write manually. There is no significant runtime overhead.
  5. Debugging: The compiler listing shows expanded Report Writer code, which can help in debugging.

Common IBM-Specific Patterns

       FD  REPORT-FILE
           RECORDING MODE IS F
           RECORD CONTAINS 133 CHARACTERS
           BLOCK CONTAINS 0 RECORDS
           REPORT IS SALES-REPORT.

The REPORT IS clause on the FD is an alternative to the separate report file record definition. When used, you do not need a 01-level record under the FD.


15.15 GnuCOBOL Report Writer Support

GnuCOBOL (formerly OpenCOBOL) supports the Report Writer module. Key considerations:

  1. Compilation: Use the -x flag for executable or -m for module. No special flags are needed for Report Writer.
  2. File handling: GnuCOBOL uses operating system files rather than mainframe datasets. The report file is a standard text file.
  3. ASA characters: GnuCOBOL can generate ASA control characters if configured, but for most non-mainframe use, you may want to omit them.
  4. Line endings: On non-mainframe systems, report files use OS-native line endings.
  5. Compatibility: GnuCOBOL's Report Writer implementation is compatible with the COBOL-85 standard. Most programs written for IBM Enterprise COBOL will compile with minor modifications.

GnuCOBOL Example Compilation

cobc -x -o salesreport example-02-control-break.cob

15.16 Common Report Patterns

Financial Statements

Financial statements typically use two-level control breaks (Division/Department or Category/Account) with SUM for revenue and expense lines. The control footings calculate net income (revenue minus expense). See the case study code for a complete example.

Audit Reports

Audit reports often use GROUP INDICATE to show exception details under audit categories. The control footings summarize finding counts and severity levels.

Management Summaries

Summary reports use GENERATE report-name (without a detail name) to suppress detail lines and print only control headings and footings. This produces a condensed view showing only subtotals and grand totals.

      * Summary reporting - no detail lines printed
           GENERATE SALES-REPORT

Inventory Listings

Inventory reports use multi-level breaks (Warehouse/Category/Item) with SUM for quantity and extended value calculations. PAGE LIMIT is set to match the target paper size, and NEXT GROUP NEXT PAGE can separate each warehouse onto its own pages.


15.17 Limitations of Report Writer

While powerful, Report Writer has limitations to be aware of:

  1. Single file output: Each report writes to exactly one file. You cannot produce multiple output files from one RD.
  2. Linear presentation: Reports are produced sequentially. Random access or non-linear output patterns are not supported.
  3. Limited conditional formatting: You cannot conditionally skip a report group type based on data values (though USE BEFORE REPORTING provides a workaround).
  4. Fixed column layout: Column positions are static. Dynamic column widths or variable-format output require manual coding.
  5. No graphics or special formatting: Report Writer produces character-based output. PDF generation, charts, or other rich formatting require external tools.
  6. Sorted input required: Control breaks require the input file to be sorted on the control fields. If the data is not sorted, results will be incorrect.
  7. Learning curve: Programmers unfamiliar with Report Writer may find the declarative model unfamiliar, particularly the SUM rollup mechanism and the interaction between PROCEDURE DIVISION and REPORT SECTION.
  8. Debugging complexity: When a report does not produce expected output, debugging can be challenging because much of the processing is implicit.

15.18 Code Examples Summary

This chapter includes six complete example programs:

Example 01: Basic Report Writer (example-01-basic-report.cob)

Demonstrates the fundamental Report Writer structure: RD entry with PAGE LIMIT, Report Heading, Page Heading, Detail line with SOURCE clause, Page Footing with PAGE-COUNTER, and Report Footing. Processes an employee file to produce a formatted listing. The PROCEDURE DIVISION uses just INITIATE, GENERATE, and TERMINATE.

Example 02: Control Break Report (example-02-control-break.cob)

Adds control breaks to the basic report. Uses CONTROL IS with department as the control field. Includes Control Heading for each department and Control Footing with SUM clause for automatic subtotals. The FINAL control footing produces grand totals using SUM of SUM (rolling up department totals).

Example 03: Page Control (example-03-page-control.cob)

Focuses on detailed page layout control. Uses all PAGE LIMIT sub-clauses (HEADING, FIRST DETAIL, LAST DETAIL, FOOTING) to create precise page zones. Demonstrates both absolute and relative LINE positioning, NEXT GROUP clause for spacing between groups, and a two-level control break (Warehouse/Category) for an inventory report.

Example 04: SUM and RESET ON (example-04-sum-counter.cob)

Demonstrates advanced accumulation features. Shows SUM at multiple control levels (Branch and Region), SUM of SUM for rollup, and running totals maintained in WORKING-STORAGE that display alongside Report Writer's automatic accumulation. Includes calculated fields (commission) and running total columns.

Example 05: Multi-Level Control Break (example-05-multi-level.cob)

The most comprehensive example. Three control levels (Region/Branch/Department) with control headings and footings at each level plus FINAL. Demonstrates GROUP INDICATE for clean output, USE BEFORE REPORTING declaratives for record counts, and complete SUM rollup from department through region to grand totals.

Example 06: Manual Report for Comparison (example-06-manual-report.cob)

Produces the same report as Example 02 but without Report Writer. Uses manual control break detection, manual accumulation and reset, manual page overflow handling, and explicit WRITE statements. Demonstrates the code volume and complexity that Report Writer eliminates. Compare this program's PROCEDURE DIVISION and WORKING-STORAGE with Example 02 to understand the value proposition.


15.19 Best Practices

  1. Always sort input data on control fields before running a Report Writer program. Use a preceding SORT step in your JCL or an internal SORT.

  2. Name your report groups (the 01-level entries) for clarity and for USE BEFORE REPORTING references. While unnamed groups work, named groups improve readability.

  3. Name SUM source fields in detail lines. The SUM clause references these names; meaningful names make the rollup chain clear.

  4. Use USE BEFORE REPORTING for record counts and calculated fields that are not simple SUMs. Do not try to force everything into SUM clauses.

  5. Set PAGE LIMIT parameters carefully. Allocate adequate space between LAST DETAIL and FOOTING for control footings, especially when you have multiple control levels.

  6. Test with varying data volumes: one record, a few records, exactly one page, a few pages, and many pages. Page boundary behavior is the most common source of Report Writer bugs.

  7. Test control break boundaries: ensure that control breaks at the top of a page, bottom of a page, and with single-record groups all produce correct output.

  8. Use NEXT GROUP to create visual separation between groups. This improves readability for long reports.

  9. Keep GROUP INDICATE for control fields in the detail line to reduce visual clutter.

  10. Document the control hierarchy in program comments. The relationship between CONTROL IS fields, control headings, control footings, and SUM chains should be clear to the next programmer.


Summary

The Report Writer module transforms report generation from a procedural task requiring hundreds of lines of control logic into a declarative description of the desired output. By defining report groups with TYPE IS clauses and using SUM for automatic accumulation, you can produce complex multi-level control break reports with minimal procedural code.

Key concepts to remember:

  • RD entry defines page layout (PAGE LIMIT) and control hierarchy (CONTROL IS).
  • Seven report group types cover every part of a report: RH, PH, CH, DE, CF, PF, RF.
  • LINE and COLUMN clauses position items on the page.
  • SOURCE connects report items to data fields; SUM provides automatic accumulation; VALUE provides literals.
  • INITIATE, GENERATE, TERMINATE are the only PROCEDURE DIVISION verbs needed.
  • USE BEFORE REPORTING provides an escape hatch for custom logic.
  • SUM of SUM creates rollup chains from detail to grand total.
  • GROUP INDICATE suppresses repeated values for clean output.
  • Report Writer handles page overflow, control break detection, subtotal accumulation, and subtotal reset automatically.

Whether maintaining legacy systems or writing new reports, Report Writer remains a valuable tool in the COBOL programmer's arsenal. Its declarative approach reduces code volume, simplifies maintenance, and eliminates entire classes of bugs related to page overflow and control break management.