COBOL Report Writer will not act until your program executes a procedural statement. Three main commands or "verbs", INITIATE, GENERATE,
and TERMINATE, are sufficient to produce most of the output from your Report Descriptions. INITIATE and TERMINATE are performed at the beginning
and the end, respectively, of the processing for your report; while GENERATE is executed repeatedly, producing one DETAIL (except in summary reporting),
preceded by any of the other TYPEs of group that may be needed as page breaks and/or control breaks are encountered.
Of the remaining procedural statements, the USE BEFORE REPORTING directive (see 4.7) enables you to write a section of code in the DECLARATIVES portion that is to be performed automatically just before the specified report group is output, and the report writer SET statements (see 4.4) make it possible to place report groups irregularly on the page.
with the following basic plan for the PROCEDURE DIVISION:
The following table lists the PROCEDURE DIVISION elements associated with COBOL Report Writer with a summary of their purposes. The third and fourth columns tell you whether or not the item is part of the current standard (ANS 85) COBOL and, if so, whether COBOL Report Writer extends the facilities.
GENERATE Statement: Coding Rules
If GENERATE detail-group-name is coded, it must be the name of a DETAIL group coded in the current program, or in a GLOBAL report defined in a containing program. (The group-name appears immediately after the 01 level-number.) You may qualify the detail-group-name with the report-name, as in: GENERATE MAIN-DETAIL IN SUMMARY-REPORT. This is necessary if your detail-group-name is not unique in the REPORT SECTION.
The form GENERATE report-name has a special significance and is known as summary reporting. It causes any DETAIL group to be suppressed, so do not use this form unless you require only CONTROL HEADING or CONTROL FOOTING groups in the body of the report at the point that you execute the GENERATE. If you use this form, you must have at least one CONTROL HEADING or CONTROL FOOTING group in the report.
GENERATE must not appear in a USE BEFORE REPORTING Declarative SECTION.
It tests for control breaks, producing CONTROL FOOTING and HEADING groups where necessary,
It performs a page-fit test, outputting PAGE FOOTING and PAGE HEADING groups where necessary; (these may also be produced as a result of a CONTROL HEADING or CONTROL FOOTING),
It generates each line in the DETAIL group, unless you are doing summary reporting (GENERATE report-name).
Once a report has been INITIATEd, your program may execute any number of GENERATE statements for each DETAIL group in the report. If your Report Description contains several DETAIL groups, you may code a sequence of different GENERATE statements in any part of the program and, in this way, build up any required report layout. You may also write a GENERATE for the same DETAIL group in more than one place in the program.
Summary reporting, where you code the report-name instead of a DETAIL group-name after the GENERATE, has the following effects:
No DETAIL group is output.
Any rolling forward of SUM operands takes place as usual, except for any rolling forward from a DETAIL group.
Any cross-footing of SUM operands takes place as usual, except for cross-footing within a DETAIL group.
Any subtotalling of (non-REPORT SECTION) SUM operands is executed as follows:
i. If SOURCE SUM correlation is in effect, all the SUM operands that correspond to a SOURCE operand in a DETAIL group are added into their totals, as though you had GENERATEd each DETAIL group in turn. Any non-REPORT SECTION SUM operands that do not correspond to a SOURCE operand are added into the totals once.
ii. If SOURCE SUM correlation is not in effect, the SUM operands are added into the totals once.
Testing for control breaks takes place as usual. If a control break is detected, any CONTROL FOOTING and/or CONTROL HEADING groups are output as usual, together with any PAGE FOOTING and/or PAGE HEADING groups that may be required as the result of a page advance.
The GENERATE report-name statement can therefore only produce output (a) on the first GENERATE after an INITIATE, and (b) after a control break.
Between an INITIATE and TERMINATE, your program may execute both the GENERATE report-name and the GENERATE group-name forms of the statement.
The following example illustrates the different effects of the GENERATE report-name and GENERATE group-name clauses:
GENERATE Processing Cycle
The following is a more thorough description of each stage in the execution of a GENERATE statement:
If the identifier form of the LAST DETAIL sub-clause is used, its value is checked and, if valid, is stored in the Report Control Area.
If your report is associated with a DUPLICATED file, the value of REPORT-NUMBER is examined to see whether it is the same as it was for the previous GENERATE for this report, thus checking that the correct duplicate of the report is in the main Report Control Area. If not, this is swapped in.
If the report has not yet been INITIATEd, run time error diagnostic 14 is logged.
If this is the first GENERATE since the INITIATE:
If there is a REPORT HEADING group, this is produced.
If there are any CONTROL HEADING groups, each of them is produced, from highest down to lowest, and the initial value of each control is saved.
If this is not the first GENERATE since the INITIATE, each control identifier is compared with the corresponding saved previous value, beginning with the highest level. If no control has changed, no special action takes place. If a difference in value (a control break) is detected, comparison ceases and the following control break action takes place:
The value of each control-id is temporarily altered to the value it had immediately before the control break;
CONTROL FOOTING groups are produced, from the lowest up to the one at the level of the control break, if any;
The value of each control-id is restored to its value after the control break;
CONTROL HEADING groups are produced from the one at the level of the control break, if any, down to the lowest.
Since CONTROL HEADING and CONTROL FOOTING groups are independent report groups in their own right, several of the same operations described below will be applied to them as for a DETAIL group, namely: the output of any pending REPEATED groups, page-fit test, storing of the latest value of the CODE (not done for CONTROL FOOTINGs), all types of totalling, performing of USE BEFORE REPORTING section, production of print lines and clearing of totals, plus the setting on of any PRESENT AFTER (or GROUP INDICATE) flags, when appropriate.
If there are any REPEATED groups in this report other than the current DETAIL, a check is made whether any have been buffered. If so, they are first output and the buffer is cleared.
If there are any cross-foot totals for this group, they are computed in the order implied by any inter-dependencies among them.
If OSVS is in effect any additional summing is now performed for the group with the following possible actions:
If there is any general "subtotalling" for the report (SUM clauses with non-REPORT SECTION operands, without UPON, and with no SOURCE SUM correlation), each SUM's operands are added into the total fields. If you are generating a DETAIL group which is absent because of a PRESENT/ ABSENT WHEN/AFTER clause in the 01-level entry, this general subtotalling is also skipped.
If there is any special subtotalling triggered by this DETAIL group due either to an UPON phrase referring to this group or to SOURCE SUM correlation that implies this group, the SUM operands are added into the total fields.
If there is a SUM clause in another group referring to an entry in this group, then rolling forward of values into its total field takes place.
If there is a USE BEFORE REPORTING section for this group in the DECLARATIVES, it is performed. If PRINT-SWITCH is non-zero as a result (meaning that printing is to be SUPPRESSed), then
If OSVS is in effect no further action takes place for this group;
If NOOSVS is in effect in effect then if no further totalling to be performed for this group, no further action takes place; otherwise the only further steps to be performed are 10 (PRESENT at 01-level), if applicable, and 8 (totalling).
If there is a PRESENT/ABSENT WHEN or PRESENT/ABSENT AFTER clause at the 01-level of this group, a test is made of the condition and, if the group is absent then
If OSVS is in effect no further action takes place for this group;
If NOOSVS is in effect then, if there is no general subtotalling to be performed, no further action takes place; otherwise the only further step to be performed is 8(a) (general subtotalling).
If there is an identifier form of a CODE clause in the RD, the contents of the identifier are moved to the CODE-VALUE location in the Report Control Area .
If this group has a REPEATED clause, the REPEATED buffer is prepared to receive the next instance of the group or, if this group is the last of the set, to produce the buffered groups alongside it.
If any lines are being produced and the report has a PAGE clause, a page-fit test is performed to test LINE-COUNTER, to establish whether or not a page advance is required before the group may be output. If the group has a MULTIPLE PAGE clause, this test is performed for the first and each subsequent line (or group of lines with NO MULTIPLE PAGE).
If a page advance is required, the following action takes place:
The PAGE FOOTING group is produced, if one exists;
PAGE-COUNTER is incremented by 1;
A form feed is output or, if an Independent Report File Handler is in use, a value of zero is placed in the current position location to cause this;
The PAGE HEADING group is produced, if one exists;
If there are any CONTROL HEADING groups specifying OR PAGE, they are produced, from highest down to lowest.
If NOOSVS is in effect and there is any further summing to be performed for this group, step 8 (subtotalling and rolling forward) is now executed.
Each report line field is stored in its report line, invoking FUNCTION routines where necessary and checking for column overlap, line overflow and any other possible error conditions, and then output. If an Independent Report File Handler is in use, it is invoked; otherwise, report writer issues a WRITE for each report line. In either case, LINE-COUNTER is first set to the target line position just before each line is produced.
If the group has a NEXT GROUP clause, LINE-COUNTER may be adjusted in accordance with the rules for that clause. (See NEXT GROUP Clause.) In the case of NEXT GROUP absolute, this may be deferred by setting the Saved Next Group Integer.
All total fields defined in this group are reset to zero, unless they are not PRESENT during this GENERATE or have a RESET phrase that defers resetting to a higher control break.
If there are any PRESENT AFTER (or GROUP INDICATE) clauses in the group, their indicators are set off.
INITIATE Statement: Coding Rules
Each report-name must be the name of a report in the current program, or that of a GLOBAL report defined in a containing program. (The report-name appears immediately after the RD level-indicator and also in the REPORT clause in the FD.)
If the UPON phrase is present, each report-name must be defined in a REPORT(S) clause in the FD of the specified file-name. The UPON phrase must be used if any of the report-names is defined in more than one FD entry.
INITIATE must not appear in a USE BEFORE REPORTING Declarative.
An OPEN for the corresponding report file must have been executed before the INITIATE is executed. The INITIATE does not OPEN the file. You may however execute an INITIATE once again for a report that was TERMINATEd without closing and re-opening the file. This fact may be used repeatedly to obtain REPORT FOOTING and REPORT HEADING groups in the interior of the report, or to obtain a fresh page with PAGE-COUNTER reset to 1.
A CLOSE must not be issued for the file to which a report is directed once the report has been INITIATEd, unless a TERMINATE is first done.
If an UPON phrase is present, the report will be written only to the file specified.
The error flag is cleared.
If your report is associated with a DUPLICATED file and REPORT-NUMBER is zero, the remaining actions are performed for every duplicate report.
If your report is associated with an Independent Report File Handler, the file handler is invoked with an action code of 6.
If the identifier form of a LINE LIMIT clause was coded, the identifier is checked and, if valid, stored in the Report Control Area.
Other internal locations and special registers, such as the current position, "body group has appeared on page" indicator, REPEATED-COUNTER, and PAGE-COUNTER are cleared.
LINE-COUNTER is reset to zero.
PAGE-COUNTER is set to 1.
All total fields, sum overflow indicators, size error indicator and Saved Next Group integer, and PRESENT AFTER indicators, wherever appropriate, are cleared to zero.
The control break indicator is set to -1 to indicate "initial control break on INITIATE".
If a run time subroutine is used for control-break detection, the lengths of each control identifier (other than REPORT/FINAL) are determined and stored in a control area.
SET Statements: Coding Rules
Format a (SET PAGE) cannot be used unless there is (a) a WITH PAGE BUFFER clause in the SELECT ... ASSIGN clause for the associated file and (b) a PAGE LIMIT clause in the associated RD entry. (The Page Buffer feature uses an Independent Report File Handler to produce the report output and will assume MODE PRNT if there is no MODE specified in your SELECT ... ASSIGN clause. File handlers are described later (see 5.3).)
The SET LINE and SET COLUMN statements cannot be used unless there is either a WITH PAGE BUFFER clause or a WITH RANDOM PAGE clause in the SELECT ... ASSIGN clause.
If your program contains more than one Report Description, you must qualify your SET PAGE STATUS, SET LINE and SET COLUMN statements by IN or OF report-name . Without qualification, the statements are assumed to refer to your one and only Report Description.
Format b (SET LINE) is used for altering the value of LINE-COUNTER. SET LINE TO ... sets LINE-COUNTER equal to the value given and forces the next line to appear there. You can use the FIRST DETAIL form with the TO phrase. SET LINE DOWN BY ... adds to LINE-COUNTER, while SET LINE UP BY ... subtracts from it. In each case, the value that results must not be less than the FIRST DETAIL value and must not be greater than the LAST DETAIL value (or their defaults; see PAGE LIMIT Clause). If you use SET LINE to decrease LINE-COUNTER, your report's PAGE STATUS must be HOLD.
Format c (SET COLUMN) is used for altering the value of the horizontal margin. SET COLUMN TO ... sets it equal to the value given. SET COLUMN RIGHT BY ... adds to it, while SET COLUMN LEFT BY ... subtracts from it. In each case, the value that results must not be less than one and must not be greater than the LINE LIMIT, and any group produced must fit within the LINE LIMIT when the new left margin, resulting from SET COLUMN, is taken into account.
You cannot use any of these SET statements until a report is in an INITIATEd state.
Because groups A and B can be of any size, it is practically impossible to define the layout line-by-line. The design has an attractiveness born of a revolt against slavish acceptance of the dictum that "printers cannot move backwards". The best way to take advantage of the facility is to GENERATE report groups as their data becomes conveniently available, addressing the page in random-access fashion. The Page Buffer facility enables you write code such as:
In fact, using this facility, you may return to any part of the page. You may also shift a group laterally (left or right) using SET COLUMN.
You can issue the SET PAGE STATUS TO HOLD at any time - not just at the start of the page. You can then return to any vertical position on or below the position where you issue this command.
You may use the SET statements in a Declarative section. In this way you may re-position a non-DETAIL report group such as a CONTROL FOOTING, HOLD the page at the start of a PAGE HEADING, and so on.
When the report is in HOLD status, LINE-COUNTER advances as usual. Report writer performs the page-fit test on body (DETAIL and CH/CH) groups in the normal way by checking the value of LINE-COUNTER against the size of the group about to be printed. If the group cannot be fitted on the page, report writer will execute a page advance despite the HOLD status. NEXT GROUP NEXT PAGE and LINE NEXT PAGE work as normal. When a page advance takes place, all the lines in the page buffer are first printed. No data will be lost. The new page will still have HOLD status.
HOLD status does not change any of the logical processes of report writer. It just makes it legal for you to return to a higher line using the SET LINE statement. HOLD status only defers the actual time when output occurs, but the end result is always the same. For efficiency, the best time to RELEASE a page is just after the last upward SET LINE on a page.
You cancel HOLD status by means of the SET PAGE STATUS TO RELEASE statement. The page buffer will then gradually be emptied as you write more lines, until such a time as a page advance takes place or the report is TERMINATEd.
The effect of SET LINE is cancelled by a page advance (except before the first page - SET LINE can therefore be done immediately after INITIATE).
If the left margin has been set greater than 1, all the lines produced for the current page will be shifted to the right by the additional factor. For example, if you issue SET COLUMN TO 5, then "COLUMN 1" in any print line is actually positioned on column 5.
When report writer executes a page advance it resets the left hand margin to 1. Your SET COLUMN statements are therefore effective only within the current page.
The example on the following page shows how you may set up a page in "snaking columns" and then place a border around the whole page:
The following coding is suitable for this problem:
SUPPRESS PRINTING Statement
The SUPPRESS PRINTING statement enables you to prevent a particular report group from being output on a particular occasion.
SUPPRESS PRINTING Statement: Coding Rules
The SUPPRESS statement may be coded only in a USE BEFORE REPORTING Declarative SECTION.
The form MOVE 1 TO PRINT-SWITCH is an alternative IBM extension that means the same as SUPPRESS PRINTING. You may also write MOVE 0 TO PRINT-SWITCH to undo the effect of a MOVE 1 TO PRINT-SWITCH or SUPPRESS PRINTING, and generally treat PRINT-SWITCH as a numeric location, implicitly defined in your program.
For example, you may use SUPPRESS PRINTING to "restart" your report after a breakdown. Simply write a USE BEFORE REPORTING section for every group and SUPPRESS each group until your program clears a flag. Your report will now be in the same internal state as when output really took place.
Each execution of a SUPPRESS PRINTING or MOVE 1 TO PRINT-SWITCH will prevent output only on that single occasion. Report writer will reset PRINT-SWITCH to zero after each excursion into your USE BEFORE REPORTING section.
In USE BEFORE REPORTING there are further examples of SUPPRESS PRINTING.
TERMINATE Statement: Coding Rules
Each report-name must be the name of a report in the current program, or that of a GLOBAL report defined in a containing program. (The report-name appears immediately after the RD level-indicator and also in the REPORT clause in the corresponding FD.)
The TERMINATE statement clears any pending REPEATED groups or Page Buffer contents. It also outputs any final CONTROL FOOTING, PAGE FOOTING and REPORT FOOTING groups that may be required at the end of the report. It then returns the report to an "uninitiated" state. PAGE-COUNTER and LINE-COUNTER will contain the final values they attained at the end of the report, but total fields will be zero (except under erroneous circumstances - see the end of (3c) SUM Clause).
A separate, subsequent CLOSE should be executed for the associated report file. TERMINATE does not CLOSE the file.
If a TERMINATE is executed without any GENERATE statements being executed for the report since the INITIATE was executed, no output at all is produced. If you wish to ensure that at least the REPORT HEADING and REPORT FOOTING groups appear, you should in this case GENERATE a blank DETAIL group before the TERMINATE.
A report may be TERMINATEd and then INITIATEd again any number of times without closing the report file. The new INITIATE causes PAGE-COUNTER to return to 1 and, if the report has a PAGE LIMIT clause, will re-commence the report on a fresh page.
If your report is DUPLICATED and REPORT-NUMBER is zero, the actions that follow are performed for each duplicate report.
If at least one GENERATE has been performed (indicated by the control break indicator being non-negative), the value of each control-id is temporarily altered to the value it had when the last GENERATE was executed, whilst each CONTROL FOOTING group is produced, from lowest to highest.
If any REPEATED groups are present, any buffered groups are output and the REPEATED buffer is flushed. Also, if the Page Buffer contains any data, this is output.
If a PAGE FOOTING group is present, it is produced.
If a REPORT FOOTING group is present, it is produced.
If your report is associated with an Independent Report File Handler, the file handler is invoked with an action code of 8. (If your report is DUPLICATED, this will only take place for reports that have been INITIATEd.)
The current vertical position location is set to -1 to indicate "report not initiated".
If any total fields are still non-zero, indicating that they have not all been output, an error diagnostic 15 is signalled.
If normal batch printing is in effect, a check is made of the error diagnostic flag and an appropriate run time error message is logged if necessary.
where declarative-section is defined as:
USE BEFORE REPORTING Directive: Coding Rules
The format above shows the PROCEDURE DIVISION and DECLARATIVES headers for the sake of completeness. They are used not just by report writer, and your program might already have Declarative sections for some other purpose. It is the distinctive format of the USE BEFORE REPORTING directive that tells report writer that the section is part of its responsibility. If you also have other Declarative sections, they may be intermixed with your USE BEFORE REPORTING sections in any order.
In order to code a USE BEFORE REPORTING section, you must ensure that the corresponding group has an 01-level data-name, so that you can refer to it as the report-group-name.
Your USE BEFORE REPORTING section may also PERFORM other sections. These are normally additional sections within the DECLARATIVES portion (as required by all ANS Standards). For this purpose, you may code additional sections within DECLARATIVES that have no USE statement. Report writer also allows your USE BEFORE REPORTING section to PERFORM sections in your mainline PROCEDURE DIVISION.
The example that follows shows how you may code one section to be performed when one of two report groups is about to be produced:
Your USE BEFORE REPORTING section must not contain any INITIATE, GENERATE, or TERMINATE statements. Neither may any of the sections it may perform.
If you specify GLOBAL, the named report group must exist either in the current program or in a contained program.
After the testing of control breaks and the production of any CONTROL FOOTING and CONTROL HEADING groups (if your group is a DETAIL);
After the computation of your group's cross-foot totals (if any), so your USE BEFORE REPORTING section can reference them;
If OSVS is in effect, after the rolling forward into your totals and subtotalling associated with your group;
If NOOSVS is in effect, before the rolling forward into your totals and subtotalling associated with your group, so your USE BEFORE REPORTING section can alter values that are due to be added into other groups' totals;
Before the moving of any CODE identifier, so your USE BEFORE REPORTING section can change the originating identifier;
Before the page-fit test and the production of any PAGE FOOTING and PAGE HEADING groups (if your group is a body group), so you may alter the originating fields due to be moved into them, or suppress them along with the body group itself.
Before any of the SOURCE, SUM, or FUNCTION fields are set up in the lines of your group, so you may change any of the originating fields due to be displayed in your group.
You may include the statement SUPPRESS PRINTING or MOVE 1 TO PRINT-SWITCH in a USE BEFORE REPORTING Declarative, in order to prevent output for the group at that instant (see 4.5).
USE BEFORE REPORTING sections were used a great deal in the ANS-68 and ANS-74 COBOL report writer. So you may possess migrated programs that contain cases of their use. With report writer much of their functions are now performed by the PRESENT WHEN and PRESENT AFTER clauses. However, they can still be of considerable use. For example:
You could use your Declarative section to WRITE additional records to another file, using the automatic control break processing to "drive" the rest of your program.
You might use the USE BEFORE REPORTING section for a CONTROL HEADING group to READ an additional record at the start of each new CONTROL value, or fetch it from your database.
You might need to suppress the printing of certain totals without preventing them from being reset to zero. (The PRESENT clause will prevent the resetting of a total field if it was not output.)
You might want to force a CONTROL HEADING group to start on a new page under certain complex circumstances. Your USE BEFORE REPORTING section would then force page advance processing thus:
You might want to search a table for a corresponding text field at the start of each CONTROL HEADING group, and move it to a WORKING-STORAGE field that is the operand of a SOURCE in a PAGE HEADING or the CONTROL HEADING itself. (If your group is a DETAIL, it will be clearer to do this in the main-line program.)
There may be an item associated with a control which is not itself a control (such as a STATE-NAME logically associated with a STATE-NO control) which you will want to output during CONTROL FOOTING time. Since the item is not a control you will not automatically obtain the before-the-break value. You could code a Declarative section for the corresponding CONTROL HEADING group. This would save the current value of the field in a WORKING-STORAGE location which is then used instead of the input item in all SOURCE clauses in PAGE HEADING, PAGE FOOTING and CONTROL FOOTING groups.
If you have no CONTROL HEADING group, you may code one as a "dummy" (see 3.2) with no LINE clauses, in order to take advantage of report writer's automatic control break checking, as suggested in the following example:
You may find it desirable to suppress printing of a minor CONTROL FOOTING if only one DETAIL is printed above it, since a "total" of a single value will seem out of place. Here is one way to do it:
Do not instead code an ABSENT WHEN clause at the 01-level of the CONTROL FOOTING group, as this would have the undesirable side-effect of preventing the resetting and rolling forward of any SUM fields that you might have defined in the CONTROL FOOTING group.
If you specify GLOBAL, your Declarative section will apply both to the current program, if it contains a report group of that name, and also to any contained program that has a report group of that name but no USE BEFORE REPORTING section of its own for that name. If a contained program also has a USE GLOBAL BEFORE REPORTING section for the same report-group-name, this overrides the effect of original section until the end of the contained program.