Introduction and Tutorial
This first part is a short introduction to the principles of COBOL Report Writer. After reading it, you will be able to write or maintain simple report writer code and you will have enough appreciation of the more advanced concepts to be able to locate the information quickly in the main parts.
¶ To improve programmer productivity in all aspects of printed output in COBOL by encouraging both experienced users and newcomers to make more use of COBOL's report writer feature.
¶ To help users who have had experience with a version of COBOL report writer that was an integral part of the compiler and want to continue to use the same facilities.
Report writer appeared in its original form in 1961 and later entered the 1968 ANS Standard. This version provided certain basic features that users of accounting machines were accustomed to, such as simple accumulation, cross-footing, and counter-rolling, as well as automatic page numbering. The implementation of report writer described in this volume contains all the facilities of the standard ANS-68, ANS-74, and ANS-85 report writer, plus IBM extensions, and includes many additional features which were added in various stages since 1974, many of which appear in the proposed ANS-9x standard. It is more suitable for the more varied and complex outputs needed by modern applications.
COBOL Report Writer also has many completely new features that are not a part of these standards, as well as enhancements to the original features. A summary list of all the enhancements will be found at the start of parts 2, 3, and 4, and in Appendix A. Those ANS-68 features that were deleted or changed in the ANS-74 and ANS-85 Standards are nevertheless retained in this product; these retentions are also listed in Appendix A.
¶ Pay slips and paychecks printed on a mainframe printer;
¶ Invoices printed by a small remote printer;
¶ A small summary print produced at the end of a large update program;
¶ Sales of golf shoes, summarized by region and area, during the years 1985 to 1992 (a one-time, ad hoc report);
¶ An extremely complex print of personnel records with many variable-length lines and fields, "printed" on microfiche.
The only requirements for a report are that it should be readable (all fields USAGE DISPLAY only) and should consist of output only.
Report writer automatically generates your print record descriptions, your intermediate data areas, and all the procedural code needed to produce your outputs, saving you the effort that elementary COBOL would have required. For particularly difficult or challenging layouts, there are more advanced data clauses. By studying these in the later parts of this publication, you will learn to produce all your outputs with COBOL Report Writer.
Although so much is performed automatically, you still retain control at the highest level over all operations, because no report writer action takes place until one of the statements INITIATE, GENERATE, or TERMINATE is executed. However, these statements are sufficiently high-level to require only the simplest logic in your PROCEDURE DIVISION.
Since you may use COBOL Report Writer in any COBOL program, you may use it in any program that has to produce readable output - even if the program performs many other tasks. COBOL Report Writer does not extract the input data itself, unlike a report generator, which means that it may be used in partnership with all types of COBOL input: standard files, databases, and subroutine or module linkage.
Your first task is to divide up the layout into report groups. A report group is a "block" of lines, produced in one operation. Your layout may be built up from any number of different report groups. You can allow the shape and contents of each report group to vary as much as you like but, if the variations become very complex, it will be easier to define two different report groups. The following guidelines should be used to define a report group:
¶ It may consist of from one up to any number of lines, and may have any number of fields.
¶ It normally fits on one page, rather than being split by a page boundary. There are exceptions to this rule in MULTIPLE PAGE groups and REPORT HEADING and FOOTING groups, described later.
¶ It may contain fields whose contents come from anywhere in the DATA DIVISION, provided that all the fields are present in memory at the moment your program generates the report group.
If your report structure corresponds to records in a main file or database, remember that, unless you have a special reason for reading ahead and buffering several records, a report group should correspond to one record from your main file or database. (However, there is also a summary reporting feature that enables your program to output one report group that summarizes a whole set of records.)
Mark each report group clearly. Only one instance of each group needs to be marked, because only one description of each group is needed. You might use square brackets in the margin of your layout. In this example, let's draw a "box" round each report group.
Here is the result:
There are three instances of report group (B) in the picture. Only one instance needs a "box", and it is best to draw it around the most complex case, that is, the instance with the extra line "**OUT OF STOCK". (We want this line to be part of the same report group, rather than a report group in its own right, because we want to ensure that it will never be separated from the preceding line by a page advance.)
Each TYPE is optional. Your report may contain any number of different DETAIL groups, any number of different CONTROL HEADING and CONTROL FOOTING groups (up to one of each for each control level), but only one of each of the other four.
We can now assign the correct TYPEs to each group in our layout:
Step 3: Code the RD Entry
Your report groups are described in the REPORT SECTION, which is the last section in your program's DATA DIVISION. The REPORT SECTION may contain any number of Report Descriptions. Each of these begins with an RD entry that starts in the A-margin:
Follow this with a report-name of your choice. This name will be used to stand for the report as a whole, so choose a name that is appropriate:
Several clauses may follow your report-name. The optional LINE LIMIT clause gives the maximum number of columns you expect per line and is used as a safety measure against losing data due to line overflow. The FIRST DETAIL clause (or its alternative spellings FIRST DE or FIRST BODY GROUP) indicates on which line the main information of each page should start. The PAGE LIMIT clause is required if your report is divided into pages. It gives the maximum number of lines to be written to each page. The order in which you code these clauses and phrases does not matter.
There are other clauses available to mark out different regions of the page. (See PAGE LIMIT Clause.)
Our report has control totals. That is, after the change in value of a certain control field (DEPOT), we want COBOL Report Writer to produce an extra report group (the CONTROL FOOTING). The data must arrive in the correct sequence as COBOL Report Writer does not SORT your data itself. (You might use COBOL SORT for that.) The field is called a control and a change in its value is called a control break. You may nest as many different levels of control as you need. You may also have corresponding CONTROL HEADING groups to appear before the start of the detail lines for the new control value. (In our example, there is just one level of control and no CONTROL HEADING group). You indicate which fields are to be used to test for control breaks by means of the CONTROL (or CONTROLS) clause. Each control represents a different level. Your controls must be listed in hierarchical order from highest down to lowest. In our example it is simple because there is only one level:
Because the CONTROL clause is the last clause of the RD entry, you write a period (".") after it. Here is another example of a CONTROL clause. This time, we have two control fields and also a special all-encompassing level, known as REPORT or FINAL, that may be used for producing grand totals for the whole report.
LINE LIMIT, FIRST DETAIL, PAGE LIMIT, and CONTROL are not the only clauses you can write in the RD entry. The others are described in the chapter Report Files and RD Entries. The order in which you code the RD clauses is irrelevant.
Each report group is coded as a series of COBOL entries. Each entry consists of a level-number, an optional data-name, any number of optional clauses, and a period. Each report group must start with a 01 level-number in the A-margin:
If the group is a DETAIL, follow this with a report-group data-name of your choice, followed by the optional word TYPE and the type of the group:
To make your program even clearer, you may spell out the TYPE clause in full; for instance: TYPE IS PAGE HEADING. Any number of entries, indicated by our "...", may follow the 01-level entry, as you will shortly see.
You indicate which level of CONTROL HEADING and CONTROL FOOTING you are describing by writing FOR name-of-control after CH and CF. (This is optional if there is only one level, or you want ALL levels in a CONTROL FOOTING). Taking our example with three levels above, you might code:
After the LINE or COL keyword you may choose one of two ways to specify positioning for your line or field by writing either integer or +integer.
¶ LINE integer gives you an absolute, that is, fixed, LINE position, counting from 1 at the top of the page, to the maximum given in your PAGE LIMIT. If you use absolute LINE clauses in a group, the integers must increase. You might use this form for the PAGE HEADING in our example.
¶ LINE + integer (+ can also be written PLUS) gives you a relative LINE position. It will cause the vertical position to move down
that number of lines. For example, LINE + 1 means place on the next line. LINE + 2 means leave one blank line. (This form is rather like
WRITE... AFTER ADVANCING..., translated entirely into data terms, of course.) You may mix absolute and relative LINE clauses in the same report group, provided that
you begin with an absolute LINE. LINE alone implies LINE + 1.
¶ COLUMN integer gives you an absolute, i.e. fixed, COLUMN position for the left-hand character of the field, counting character positions from 1 at the left, up to the maximum given in your LINE LIMIT. You can also anchor the field at its CENTER column by writing COLUMN CENTER integer, and you can fix the field at its RIGHT column by writing COLUMN RIGHT integer. If you use these absolute COLUMN clauses, the integers must increase within a LINE.
¶ COLUMN + integer (COLUMN can be shortened to COL and + can be written PLUS) gives you a relative COLUMN position. It will cause the current horizontal position to move right that number of positions from the last column of the preceding field (from zero if this is the first field) to the first column of the current field. For example, COL + 1 means place this field in the next column without a gap, and COL + 2 means leave one column blank.
COBOL Report Writer writes your report groups vertically down the page in the order in which they are GENERATEd. DETAIL and CONTROL groups (HEADING or FOOTING), which are known as body groups, are first checked to see whether all their lines will fit on the current page. If your report group begins with an absolute LINE, report writer will advance to a new page if that LINE number has been reached or passed. If your report group begins with a relative LINE, report writer checks the size of the report group. If there is no room, or if there is not enough room for the whole group, report writer will advance to a new page.
Advancing to a new page involves automatically generating your PAGE FOOTING, if you defined one, followed by your PAGE HEADING, if you defined one. If a body group (CH, DE or CF) begins with a relative LINE, it is positioned on the FIRST DETAIL line, irrespective of the value in the LINE clause. (If you did not code a FIRST DETAIL sub-clause, it is assumed to be the line immediately following our PAGE HEADING, or line 1 if there is no PAGE HEADING.)
If the contents of the field consist of fixed text, write:
If the contents of the report field come from a field in your COBOL DATA DIVISION, write:
Your SOURCE field may be defined in any section of your DATA DIVISION, or it may be a special register such as LINE-COUNTER. The SOURCE keyword may be omitted. You may use subscripts and qualifiers, for example: SOURCE BACK-PAY IN MASTER-RECORD (4). You may also use arithmetic expressions and the word ROUNDED , if needed; for example:
You must code a PICTURE clause with the SOURCE clause. This specifies the format in which you would like the field displayed and is the same clause as in elementary COBOL. It can be abbreviated as PIC. Here are two examples:
The rules for storing the field work exactly as for the MOVE (or the COMPUTE) statement of elementary COBOL. If your SOURCE refers to a CONTROL field, then you will obtain the value before the control break if report writer is currently processing CONTROL FOOTING groups. This is the only case where you do not obtain the value contained in the field at that instant.
Your layout may require a page number. This is held in a special register (a dedicated internal COBOL location) called PAGE-COUNTER. This location is set up automatically by report writer. There are also LINE-COUNTER and COLUMN-COUNTER special registers.
Suppose that the record that supplies data for the layout above is defined in a standard file as follows:
Now we are ready to complete the PAGE HEADING group and the first line of the DETAIL group for the layout above, using these new clauses.
Step 4D: Conditional Items
There is one item in our layout that we do not want to produce every time. This is the message "OUT OF STOCK". We deliberately allowed for it by including it in the "box" we drew round the typical DETAIL group. It should only be produced if the condition
is true. To make any item depend on a condition's being true or false, use the clause:
Report writer will then automatically test the condition when it is about to produce the item. If the condition is false, the item is ignored. If you put the clause on a LINE entry, it is the whole line that is ignored. (You can in fact put it at any level. When a group field is ignored, so are all the fields within the group.) In the case here, we do want the whole line to be ignored if the condition is false, so the following would be a valid description for the second line for the DETAIL group:
Code sample (B):
Step 4E: Totalling
The sample layout tells you to produce a total in the CONTROL FOOTING group. COBOL Report Writer allows you to produce totals from virtually any numeric fields, and you may do it in any TYPE of group. To produce a total, follow these two simple steps:
1. Put a data-name at the front of the entry you want totalled.
2. In another entry, use the clause: SUM OF data-name instead of SOURCE or VALUE.
First, you must go back to our coding for the DETAIL group above and add a data-name to the entry for ORDER-VALUE. For example, you could re-write the last entry as:
where REP-ORD-VAL is a new data-name of your choice. Now you can code the CONTROL FOOTING group for our layout:
Code sample (C):
You may have any number of CONTROLS in your program, and you may have a CONTROL HEADING as well as a CONTROL FOOTING report group for each control.
Code sample (D):
Step 6: Code the PROCEDURE DIVISION
COBOL Report Writer is entirely under the control of your program, but at a higher level than is the case with elementary COBOL. This means that no action will be taken until your program executes a report writer statement. There are three of these:
This statement initializes your report at the start of the whole process. Your program must do this before it is allowed to execute any other report writer statements. It does not open the file. Name-of-report is the data-name you wrote right after the RD.
This statement generates one instance of a DETAIL report group. Detail-name is the data-name you used to name your DETAIL report group. The GENERATE also performs all the other actions that might be necessary before the DETAIL report group is output, namely:
¶ It tests for control breaks (if your report has a CONTROL clause) and, if necessary, produces CONTROL FOOTING and CONTROL FOOTING report groups.
¶ It checks that your DETAIL report group will fit completely on the current page (assuming that your report has a PAGE clause). If not, it produces your PAGE FOOTING report group (if there is one defined in your report), advances to a new page and produces your PAGE HEADING report group (if there is one defined in your report). Unless you explicitly allow it with a MULTIPLE PAGE clause, report writer never splits your report group over two pages.
If it is the first occasion after the INITIATE, the GENERATE statement will output any REPORT HEADING, your PAGE HEADING, and all your CONTROL HEADING groups before generating your DETAIL report group.
Your CONTROL HEADING and CONTROL FOOTING report groups are also subject to the page-fit test. They are treated similarly to DETAIL report groups. These three TYPEs are often referred to as body groups, because they fit into the "body" of the page (between the PAGE HEADING and FOOTING) and usually contain the most important information.
This statement ends your report and produces any final items that are required at the end of the report, namely:
¶ All CONTROL FOOTINGs up to the highest level defined;
¶ The last PAGE FOOTING (if defined);
¶ The REPORT FOOTING (if defined).
for each input record:
If your input is from a database, or reaches your program's DATA DIVISION by some means other than from a standard file, you will need to replace the OPEN and CLOSE for the input files and the READ by more appropriate statements.
To produce a more complex layout, you would probably define several different DETAIL report groups and decide in your program when to GENERATE one or the other. For our example, the following would be a suitable complete PROCEDURE DIVISION:
Code sample (E):
Place this code after the code in the code samples (D), (A), (B) and (C) (in that order) and you have a complete program.
You may use report writer "verbs" just as you would use any other PROCEDURE DIVISION statements.
So your program may do many other tasks apart from just producing
your report output.
This last approach is useful where you need to produce a report that has distinct sections, perhaps with different page headings. So a single physical report (as the end-user sees it) may consist of several different logical reports (as the programmer sees them), all written to the same file.
You can also direct your report output to a special Independent Report File Handler, designed to process the output from reports in a particular way. To use the special file handler, write the extra clause: MODE IS mnemonic-name in the SELECT clause. It does not affect the FD or any other statements in your program.
LAST DETAIL gives the last line on which a DETAIL or CONTROL HEADING report group may appear.
LAST CF (or LAST CONTROL FOOTING or just FOOTING) gives the last line on which a CONTROL FOOTING group may appear. If you do not specify it, a default value is assumed for it. You can use it to ensure that a CONTROL FOOTING will never appear at the top of a page (since there will always be space reserved for it at the bottom of the previous page).
OVERFLOW and SUM OVERFLOW enable you to specify the action that takes place if any arithmetic expressions or totals defined in your report groups are too large for the report field or involve dividing by zero.
CODE is used when your output report data must have extra unprinted information placed at the start of each record, or when you need to pass information to a special Independent Report File Handler (see below). For example, if your installation has provided a file handler to do spooling and restart, you may be required to provide a key by which restart would be done. You would then write: CODE IS name-of-key-field.
ALLOW SOURCE SUM CORR and ALLOW NO SOURCE SUM CORR determine whether the ANS-68 or the ANS-85 rules will be used for calculating certain SUM fields. ALLOW NO SOURCE SUM CORR is assumed in default in the version as supplied.
GLOBAL makes the report available to nested programs.
COBOL Report Writer keeps an internal copy of each of your control fields so that it can test for a control break by comparing them with the new values on each GENERATE. Before it produces your CONTROL FOOTING report groups, it temporarily stores these previous values back into the control fields. So if your CONTROL FOOTING refers to a control field, as a SOURCE for example, you will get the previous or pre-break value, even though the original control field has changed in value.
You may also want a major heading and a major footing at the very start and end of your report. For example, you may want to produce grand totals for the entire report. If so, you may use the reserved word REPORT or FINAL. This is the highest possible control level. If you use it, it must therefore be first in the list of controls in your CONTROLS clause.
There may be fields other than totals or lines that should be produced only once after a control break. These may be inside a report group, where you cannot make use of a separate CONTROL HEADING. You can define them by writing:
The field or line will then appear only on the first occasion after a control break at the level you indicate. (Alternatively, if you use ABSENT AFTER..., the field or line will not appear the first time and will appear every time thereafter until the next control break.) You may also write PRESENT or ABSENT AFTER NEW PAGE, indicating that you want the field or line to appear (or disappear) only on the first occasion after a page advance. Finally, you may code both the control-field and PAGE operands in one clause.
It is possible for a report to have no DETAIL groups at all. This case is called summary reporting. The only body groups coded are CONTROL FOOTING - and possibly CONTROL HEADING - groups. Therefore, since you have no name of a DETAIL group to give in your GENERATE statement, you write: GENERATE report-name.
The next example illustrates all the points made in this section. There are three levels of control, including REPORT, each with a CONTROL FOOTING.
There is much more about CONTROLS in the main section (see CONTROL Clause).
If your report needs a particularly long or complex REPORT HEADING or REPORT FOOTING, or if your report layout changes completely at a later stage, code a second separate RD
with its own Report Group Descriptions following and expand the REPORT clause of your FD to include the second report-name. (You may associate as many RDs as you like with
the same FD.) For further details, see Report Files, REPORT SECTION and RD, and Multiple Reports.
If your report has a series of fields or lines or groups of similar layout or format, it is usually possible to save time in coding by writing one multiple clause instead of several entries with single-operand clauses. Here is a list of cases:
If you have consecutive fields in a line containing literals, you may code multiple COLUMNS and VALUE clauses to avoid writing several entries:
SOURCES in Consecutive Fields, with Same PICTURE
If you have several consecutive fields in a line with the same PICTURE (or if you can expand shorter PICTUREs to match longer ones), you may code multiple COLUMNS
and SOURCE clauses in one entry:
Here, as usual, each SOURCE field is a data item defined in the DATA DIVISION of your program (in this particular case, a numeric item). VALUE and SOURCE clauses cannot be combined within the same multiple clause.
Using a single entry like this also makes it easy to total a series of fields by coding just one SUM entry:
If separate entries are used, you would have to total them by writing either: SOURCE TENNIS + GOLF + SWIMMING + CRICKET, or SUM R-TENNIS R-GOLF R-SWIMMING R-CRICKET, placing these data-names on the entries in turn.
You can also use OCCURS with a relative COLUMN to provide the gap, in which case the STEP phrase is unnecessary.
Repeating the Same VALUE
You can combine a single VALUE with an OCCURS clause or a multiple COLUMNS clause, in which case the VALUE is simply repeated:
A single-operand SOURCE field can be similarly repeated, although the occasions for doing so are rarer.
The LINE clause also has a multiple form. You may also combine an OCCURS clause with a single-operand LINE clause. (In the latter case, if you use STEP
, as you must if the LINE is absolute, it refers to the vertical distance.) If you use a SOURCE, the entire table of SOURCE items must be "read
into memory" first. Within the repeating LINE, you may have multiple VALUES and SOURCES clauses. This enables you to improve clarity by stacking your heading values in one place:
(You need not code the literals vertically like this, but it will aid the eye.)
Variable Number of Repetitions
If the number of repetitions is variable, you should use the OCCURS clause's keyword TO and DEPENDING ON phrase, whose operand can be any data-name or
arithmetic expression. Report writer will then dynamically calculate the actual number of repeats present on each occasion. It is valid for there to be no
occurrences, so your minimum can be zero. Any "unused" repeats are treated as ABSENT:
The same method can be used for LINEs. If a body group has a variable number of lines and they are all relative, report writer will take
into account only those lines actually present when applying its page-fit test.
SOURCE Items in a Table
If you need to output SOURCE items that are held in a table, report writer will automatically vary an internal data-name which you can then use as a subscript. You
can specify a FROM value for the starting point and a BY value for the increment for your subscript, but these are assumed to be 1 if you omit them:
You choose your own data-name for the VARYING clause, but it must not be defined anywhere as a data item in your program. You can reuse the same data-name many times in the REPORT SECTION, except where the VARYING clauses are nested.
You may combine VARYING with a multiple COLUMNS or LINES clause, as well as with an OCCURS clause, and you may output results in more than one dimension. In the next
example, the SPORT fields are printed in reverse order:
The REPEATED clause enables you to place whole groups side-by-side. On each GENERATE, report writer will place the group in an internal buffer, until the
last of each set arrives, whereupon the whole set will be printed side-by-side. You should define only the left-hand group.
If a different DETAIL group is GENERATEd - say SOCCER-FIXTURE - or if your program issues a TERMINATE, and there are still left-hand groups in the buffer, these buffered groups are output first, padded out with blank entries on the right where necessary.
Different Levels Using the same CONTROL FOOTING
You will have noticed from some of the preceding examples that a lower CONTROL FOOTING and a higher CONTROL FOOTING often have a very similar layout and you may wish you could code a single report group and use it for any number of control levels. You can do this simply by listing more than one control in the TYPE clause, for example TYPE CF FOR REPORT, YEAR, MONTH or just CF FOR ALL. Any SUM totals are then automatically rolled forward up to each higher level. If any CONTROL FOOTING has a different layout from the others, you can use PRESENT WHEN CONTROL IS YEAR, PRESENT WHEN CONTROL IS MONTH, and so on to vary it.
A SUM may be combined in an entry with a multiple COLUMN (or LINE) clause to give you a series of totals of another repeating entry with the same number of repetitions,
as you see in the last line of this example:
The total line may also be in a different group from the repeating line. If so, you might then remove the OCCURS 12 on the first LINE entry and GENERATE the group containing it 12 times.
As well as totalling a field using SUM, you may count the occurrences using the COUNT clause. COUNT simply adds 1 each time instead of the value of the field. You may COUNT the number of times any REPORT SECTION item appears, including LINEs or whole groups. All multiple occurrences contribute to the COUNT.
You may use SUM and COUNT as terms of a SOURCE expression. Be sure to enclose each term in parentheses. For example, to find the average amount of the subscription of our four sports above, you may write:
(As usual, the words SOURCE IS are optional.) If the divisor (the COUNT term above) happens to be zero, report writer will detect the error, unless you write OVERFLOW PROCEDURE IS OMITTED in your RD statement. The action taken depends on what, if anything, you coded in the OVERFLOW PROCEDURE clause. (By default, report writer will detect the error and write an error message on your terminal or job log, leaving the field blank.)
You may also total numeric fields directly from other sections in your DATA DIVISION. (With the older ANS COBOL report writer this method was necessary to obtain totals. You coded the name of the FILE, WORKING-STORAGE, or LINKAGE SECTION item as an operand of the SUM clause in the lowest-level CONTROL FOOTING.) With such external items, you may use subscripts, and you may also SUM an arithmetic expression; for instance:
If the item does not already appear as a SOURCE, this is the only method of totalling it. So this technique is useful where you require totals of a field but do not want to show the individual values that were added to produce the total. Its main disadvantage is that it may not be clear to the reader of your program exactly when the values are added into the total. See the remainder of this publication for a discussion of the relevant rules.
Note that the third person in our list, ANALYST, has no title because there is no WHEN OTHER ("catch-all") in the choice of titles.
You may produce many useful effects with the PRESENT WHEN clause by causing fields or lines, relative or absolute, to appear or disappear at certain times. If a relative entry (COLUMN
+ ... or LINE + ...) follows an entry that may or may not be PRESENT, its position is variable:
The ABSENT WHEN clause has the same effect as PRESENT WHEN except that you write the negative condition. Other conditional clauses are PRESENT AFTER
(previously known as GROUP INDICATE) and ABSENT AFTER. Instead of checking a standard COBOL condition, these clauses test whether there has been a page advance or a control
break since the group was last produced. You may write PRESENT AFTER NEW PAGE, PRESENT AFTER NEW control-id, or PRESENT AFTER NEW control-id OR PAGE
Some Shorter Forms
COBOL Report Writer offers you several ways to shorten the amount of code you write. You have already seen several, such as shortening COLUMN to COL . Of course, the shorter forms may not always be clearer, and you may decide not to adopt them all. Here are some of them:
The keywords TYPE, SOURCE, VALUE, and PRESENT may be omitted. This reduces your coding effort at a cost of making your program less readable to a maintenance programmer unfamiliar with report writer.
If you do not code a TYPE clause in a level-01 entry, TYPE DETAIL is implied.
You may write LINE and COLUMN (or COL) in the same entry, provided that there is only one item in the LINE. So you could code:
If there is second item in the line, this second method is the only way.
If there is another LINE in the report group, this second method is the only way.
If any of your report fields are to take up a variable number of columns, use the left-shift (or "squeeze") symbols "<" and ">" in the PICTURE. The examples below show the effect of these symbols:
The reason why PIC <9>9 was coded rather than PIC <99 against the child's age is to prevent a value of zero from causing the field to vanish completely. In the other cases, the closing ">" symbol is optional.
Now imagine this same code with all the "<" and ">" symbols removed from the
PICTUREs. This is what would appear:
As well as by using standard PICTURE symbols such as "/", "0" and "B", you can place any additional characters into your report field by placing them within "quotes" (or 'apostrophes' ) within the PICTURE. For example, to print a percentage:
COLUMN CENTER and RIGHT
You can specify the center or the right-hand column as an anchor point, rather than just the left-hand column. To do so, write COLUMN CENTER or COLUMN RIGHT. (CENTRE is an alternative spelling.) In the case of COLUMN CENTER, if your field has an even number of characters, the odd character goes on the right. This feature saves you time when you are working with fields of different lengths, in different lines, that should appear centered or right-aligned in a "stack". It also simply saves you the effort of counting out the length of a field in order to center it. See the following cases, all of which produce the same result:
If your field is variable-length, report writer first takes the actual size of the field before it positions it. In this way a name, title, etc. can be centered or
NEXT GROUP Clause
Use this clause when you want to create extra space between report groups or when you need to ensure that a particular report group is the last on the page, perhaps the CONTROL FOOTING of a major control. With report writer, this clause is necessary only with body groups. It has the useful property that, if there is a higher-level control break, the lower-level CONTROL FOOTING group does not affect the higher-level one, so that, if there is room, they normally remain together on the same page.
Write the clause in your 01-level entry for the group. The form NEXT GROUP + integer will create integer extra blank lines following the group, provided it is not the last on the page. The form NEXT GROUP NEXT PAGE causes your group to be the last on its page.
Because of the GROUP LIMIT, the CONTROL HEADING will not appear after line 57.
A CONTROL HEADING re-appears because of the new page even though no control break occurred.
MULTIPLE PAGE Groups
If you have a large vertical table to print, perhaps a summary with one line for each value encountered, you may be concerned that it will not always fit on one page. Perhaps there are usually less than 60 items but you have to allow for anything up to 1000 items! To handle this, code the clause MULTIPLE PAGE on your 01-level. Report writer will then automatically do a page advance whenever the page is full (printing PAGE FOOTING and PAGE HEADING as usual). Thus your code would be:
This feature also handles more complex layouts, perhaps a multi-page personnel profile.
The FUNCTION clause is used when you need to produce a specially formatted or converted report field that cannot be produced by SOURCE, SUM, or VALUE . Each FUNCTION corresponds to a pre-written routine that is either a built-in part of the report writer software or written by a person at your location. Examples of built-in FUNCTIONs are:
MDATE This produces the same output as DATE, but in the order: Month-Day-Year.
TIME This gives the current time.
Information about developing your own functions will be found later (see Developing User-Written Functions).
You will now not need to change your program when moving between, say, a personal system, a mainframe with a laser printer, and a mainframe with an old impact printer, except possibly to change the TYPE clause in the SELECT...ASSIGN if it is not preset as the default. Also, the STYLE clause has no effect on the COLUMN clauses or any other part of your source program.
For more advanced information on creating and using styles, see Printer Styles.
The file handler may require you to define a CODE clause in your RD statement. This clause is used to pass additional information to the file handler. Apart from this, no other change need be made to your program.
with the integer set to the maximum number of distinct reports you need.
The DUPLICATED clause causes the special register REPORT-NUMBER to be set up. You can MOVE any value into REPORT-NUMBER from 1 to your maximum number. This causes report writer to channel subsequent output to the corresponding report file. Each report is logically separate. Of course, the contents of each report are different because your program is writing to only one of the set at any given time. The layouts need not all be identical, since you are quite free to vary them conditionally in the usual way. (For example, REPORT-NUMBER could be used as a subscript or within the condition of a PRESENT WHEN clause.)
Only one FD entry is required for all the physical files associated with the multiple report. Similarly, only one OPEN and one CLOSE are required to open and close all its files. More details will be found later (see Multiple Reports).
Now you can tackle a layout such as the following:
The report groups in boxes have been defined separately. Normally you would not be able to place them alongside each other. (The REPEATED clause is not appropriate as NAME-ADDRESS-GROUP and SPORTS-GROUP are instances of different groups, not instances of the same group.) By using the Page Buffer you may now write in the PROCEDURE DIVISION of your program:
You may store the groups on the page in any order. It is also possible to change the left/right positioning of groups by means of the SET COLUMN statement. There are several other variants of SET PAGE and SET LINE (see Report Writer SET Statements).