Report Group Descriptions
This part describes in detail every aspect of the Report Group Descriptions that follow your RD entry in the REPORT SECTION. After the next section, the
sections are in alphabetical order for easy reference.
Your RD entry may be followed by any number of Report Group Descriptions, but there is a limit to the number each TYPE other than DETAIL. Each Report Group Description begins with a 01 level-number entry in the A-margin.
More information about report groups follows or may be found later in this part (see TYPE Clause).
Report Groups: Keyword Table
Report Groups: Keyword Table
where report-group-entry is defined as follows:
where multiple-choice is defined as follows:
You need not place data-names on your report group entries except in the following cases, where they are required:
On the 01-level entry of a DETAIL group, or any other group that may be referred to in the USE BEFORE REPORTING header of a Declarative SECTION (see USE BEFORE REPORTING Directive ). When a data-name is used at the 01-level, it gives a name to the entire report group and is called the report-group-name or group-name. The group-name must be unique within an RD, but you may re-use the name in another RD.
On a numeric entry referred to in a SUM clause or term. (See SUM Clause.)
On any entry at any level that is referred to in a COUNT clause or term. (See COUNT Clause.)
In all other cases it is preferable to omit data-names since an unnecessary data-name may mislead the program-reader into thinking that it is referred to in one of the ways above. It may also impede the precompiler's optimization.
The following general-purpose DATA DIVISION clauses can be used in a report group. The first four may be used at both group and elementary levels (not the 01
-level in the case of OCCURS). PICTURE and VALUE are allowed only at the elementary level.
but the following cannot be used in a report group:
any USAGE other than DISPLAY, such as:
In addition to the general DATA DIVISION clauses, report groups may contain special-purpose clauses that describe the position and contents of fields. The first four clauses, TYPE, NEXT GROUP, GROUP LIMIT, and REPEATED, can appear only at the 01-level. The special-purpose clauses are:
The clauses PICTURE, COLUMN, SOURCE, VALUE, SUM, COUNT, and FUNCTION can appear only at the elementary level.
For every entry with a COLUMN clause, there must be a LINE clause either at the same level as or at a higher level. If a given report line contains only one elementary field (and provided the entry is not a multiple-choice entry, see PRESENT WHEN Clause), you may combine the LINE and the COLUMN clauses in the same entry, for instance:
There is no limit to the number of elementary fields a report line may contain. If the report line contains several elementary fields, you must code all the COLUMN entries within the line at a lower level than the LINE entry, for example:
Not all the COLUMN clauses within a LINE need be at the same level, since some or all elementary entries might be contained within non-LINE group entries; for example:
A LINE clause must not be subordinate to another LINE clause. (If this rule is violated, the nested LINE entries will be treated as though they were defined at the same level as the first.)
If a given report group contains several lines, you must give all the LINE entries in that group a level-number other than 01. If the group contains only a single report line, you may code the LINE clause in the 01-level entry; for instance:
You may choose only one of five clauses: SOURCE, VALUE, SUM, COUNT, and FUNCTION to supply the contents of an elementary item automatically, bearing in mind that (a) SOURCE or VALUE can be repeated several times in a multiple-choice entry (see Multiple-Choice Form), and (b) SUM (see SUM Clause) or COUNT (see COUNT Clause) can be used as special operators in terms in an arithmetic expression (see SOURCE Clause).
If there is no SOURCE, VALUE, SUM/COUNT, or FUNCTION clause in an elementary item, the following conditions must be met:
The entry must have a data-name (following the level-number).
The entry must have a COLUMN clause.
If the COLUMN clause is relative, the item must have a fixed horizontal position (that is, it must follow an item with a fixed end-column, unless it is first in the line).
The item must have a PICTURE with none of the features that are unique to the REPORT SECTION (that is, "<" or ">" symbols or general insertion characters). Report writer will then expect you to fill in the report field independently with some COBOL procedural statement.
As an example, in the following case
the only way this item can receive a value is through a COBOL MOVE, ADD, ACCEPT, or other procedural statement, which is outside the scope of report writer and is left to you. Report writer will ensure that the report field is not overwritten by any other field, so any value stored in the item R-PRIOR-CUST-NO will remain there and will appear whenever the enclosing group is produced.
Note that you should not attempt to change the value of a group field, such as a report line, in this way.
You may code the clauses of any report group entry in any order, except in the case of a multiple-choice entry, where each SOURCE, VALUE, or FUNCTION operand is immediately followed by WHEN condition. Details of this combination are given later (see 3.18).
However, you may code the SUM clause more than once in the same entry. You may also code a SOURCE, VALUE, or FUNCTION
clause and its associated PRESENT/ABSENT WHEN/AFTER clause more than once in a multiple-choice entry. All other
clauses may appear no more than once in an entry.
BLANK WHEN ZERO Clause: Coding Rules
If you code BLANK WHEN ZERO in an elementary entry, the entry must have a numeric PICTURE. If you code it in a group level entry, it applies to all the numeric elementary entries within the group. (This clause is usually referred to as the BLANK WHEN ZERO clause, even though the word WHEN is optional.)
You may use BLANK WHEN ZERO even if your field is not in a fixed position. It is also permitted with a variable-length field (PICTURE symbol "<"), in which case a zero value in a variable part has a length of zero.
COLUMN Clause: Coding Rules
COLUMN with no operands is shorthand for COLUMN + 1.
For every entry with a COLUMN clause, there must be a LINE clause at the same or a higher level. So you may write:
provided that there are no other entries within LINE 5. If the line has two or more fields, you must then create a new level, as with:
If you code a COLUMN entry at the same level as the preceding LINE:
then report writer will diagnose this as invalid but will allow it as stated.
COLUMN may be the only clause in an entry. The result is a blank field whose only purpose is to shift the current horizontal position (COLUMN-COUNTER ) to the right. A blank field (absolute or relative) occupies one column's width in addition to the usual spacing for the COLUMN. It is therefore equivalent to coding a VALUE consisting of a single space alongside the COLUMN clause (although doing so would be less efficient). For example, COL + 4 coded alone in an entry shifts the current horizontal position four (not three) columns right. (See the discussion in the next section).
The size of your item is calculated from the PICTURE clause or the size of the VALUE "literal", and is used in combination with your COLUMN clause to check that: (a) the line width is not exceeded (see LINE LIMIT Clause and, if you are using automatic line wrap, see WRAP Clause), and (b) no two items overlap (unless they both carry a PRESENT WHEN/AFTER clause). If two or more items overlap in whole or in part, report writer will diagnose this as invalid but will allow the COLUMN positions and field sizes as coded. The later-coded entry will then overwrite the earlier-coded entry at run time by the number of overlapping columns and data will be lost. No run time error occurs.
Within each LINE, any absolute COLUMN numbers should be in ascending order, after the evaluation of all PRESENT WHEN and PRESENT AFTER clauses (see 3.17 and 3.18). If this rule is broken, report writer will diagnose this with a Warning (message 250) but will allow the COLUMN positions as coded.
The RIGHT and CENTER phrases cannot be coded with the + (relative) form of this clause.
You may write "+" with or without a space on either side.
COLUMN + integer-1. This is the relative form. It indicates that the horizontal position within the line is to be moved integer column positions from the last character of the preceding field to the first character of this field. Note that the "gap" before the field will be one less than the value of the integer. For example:
COLUMN + 1 = "no gap"
If you use COLUMN + integer in the first field of a line, it is treated as though you had written the absolute form, COLUMN integer-1, since the initial value of the horizontal position is zero.
COLUMN integer-2. This is the absolute form. It indicates that the left-hand column of the field must appear on that fixed position within the line. Remember that the first column in the line is COLUMN 1. LINE LIMIT is the highest possible value of integer.
COLUMNS integer-1 integer-2 ... This is the multiple form of the clause. It reduces your coding effort by including several operands in the same clause. The relative multiple form, COLUMNS + integer, + integer ..., is also allowed and you may combine both forms in the same clause. Multiple COLUMNS are described in more detail below (see 3.4.4).
COLUMN RIGHT and COLUMN CENTER are used if you wish to specify the right-hand or center position of the field as alternative anchoring points, to save you the effort of "counting out" the length of the field to establish its left-hand column when you already know its center point or right-hand column. COLUMN LEFT, the normal alignment, is provided for syntactic completeness.
If you specify COLUMN CENTER and the field is an even number of column positions wide, the extra character position goes to the right
of the central column. The following example shows the allowable alternatives for a six-character field starting in column 1:
You will get a ragged left-hand side in the case of COLUMN RIGHT and centralization with ragged left and right , in the case of COLUMN CENTER. By successively generating the following entry on different lines with different values
you will obtain
The following, generated several times with a different CITY:
gives you, for example,
Note that RIGHT and CENTER may also be used with the multiple format of the COLUMN clause discussed below (see 3.4.4).
The CENTER or RIGHT option is required if you need to center or right-align a variable-length field - (see "<" and ">" symbols) for full details. The output in the box above could also have been produced using a SOURCE item thus:
If an elementary item has no COLUMN clause then, if the OSVS precompiler option is in effect or a data-name is present, the item will not appear in the report. It is then termed an unprintable item. Unprintable items are used chiefly for summing in the following cases:
For SOURCE SUM correlation (see 3.23.5). A SOURCE clause may be written as an unprintable item because a SUM of a certain data item is required but its individual values are not:
For rolling forward of certain values into totals. This is report writer principal way of forming totals. This time the unprintable item has a data-name and the data-name is summed:
For forming totals that are not printed directly but used indirectly:
Further examples may be found in SUM Clause.
If the precompiler option is not in effect, and any elementary entry beneath the LINE level has no COLUMN clause, then COLUMN + 1 is assumed for the entry, provided that the level-number is not followed by a data-name. Thus, you could omit both COLUMN clauses in the following fragment:
Multiple COLUMNS Clause
A multiple COLUMNS clause is functionally equivalent to an ordinary COLUMN clause used in conjunction with an OCCURS clause (see 3.14); for example:
You may use VARYING to vary a counter that is used as a subscript in a SOURCE clause.
You may use a simple (single-operand) VALUE, SOURCE, SUM, or FUNCTION clause to place the same value repeatedly in each instance of the field.
You may use a multiple VALUE or SOURCE clause to place a different value in each instance of the field.
You may place a data-name at the start of the entry and SUM the data-name in another entry to produce a total of the instances or occurrences collectively or individually. (To form individual totals, there must be another multiple or occurring COLUMN clause in the entry with the SUM clause.)
Unlike the method of repetition using the OCCURS clause, the intervals between the entries defined by a multiple COLUMNS clause need not be regular.
Your multiple COLUMNS clause will be syntactically correct if it would be correct when written as a series of separate COLUMN entries.
Here are some examples of the multiple COLUMNS clause:
The following diagram and corresponding code illustrates the usefulness of the multiple COLUMNS clause:
Use of COLUMN-COUNTER
COLUMN-COUNTER indicates the current horizontal position within a line. At each stage during the processing of a line, it contains the most recent rightmost column number on which data was placed in the line. It may also be incremented by an "empty" (unprintable) entry containing only a COLUMN clause. Regardless of the number of reports and report lines it contains, each program has just one COLUMN-COUNTER.
Report writer uses COLUMN-COUNTER as a place-keeper and internal subscript while assembling variable-length or variable-position fields in a report line. For the sake of efficiency, it does not initialize or update COLUMN-COUNTER in a report line consisting of fixed-length, fixed-position fields, unless you explicitly refer to it in an item in the line.
You may use COLUMN-COUNTER in the condition of a PRESENT WHEN clause (see 3.18), or as the operand of a SOURCE clause (see 3.21), or as a parameter to a FUNCTION (see 3.7). It cannot be used in your PROCEDURE DIVISION, because the generating of each line is an indivisible operation.
COLUMN-COUNTER may be used to simplify the conditions that would otherwise be required to string together a series of conditional fields:
If your current group is a REPEATED group (see 3.19), or if you use the SET COLUMN statement of the Page Buffer feature (see SET Statements), you should bear in mind that COLUMN-COUNTER is relative to the left-hand boundary of the group. So it does not include the extra left-hand margin used to offset your REPEATED groups or the extra margin you create with SET COLUMN.
COLUMN-COUNTER should not be used in a condition where the field is to be totalled using the SUM clause, because COLUMN-COUNTER is not updated when totalling is performed at the start of processing for the group.
COUNT Clause: Coding Rules
Each data-name must be the name of any REPORT SECTION entry other than an RD. It may even be the data-name of a group entry that contains the COUNT clause.
You may place the COUNT clause in a different report group from the item counted (rolling forward) or in the same group (cross-footing). As with the SUM clause, if the COUNT clause appears in a multiple CONTROL FOOTING, all but the lowest level total is formed by rolling forward the next-lower total.
Unlike the situation with the SUM clause, the item counted need not be a numeric field.
Like the SUM clause, you may use the COUNT clause in two ways:
As a clause in its own right. You write the clause in place of a SOURCE, VALUE, or FUNCTION clause. For example:
As a term in an expression used as a SOURCE operand; for example:
You may combine SUM and COUNT terms in the same expression. For example, the following will give you the average value of all the instances of a numeric field:
COUNT Clause: Operation
The item referenced may be at any level; for example:
A 01-level entry: you will obtain the number of appearances of a particular group.
A LINE entry: you will count the number of appearances of that particular LINE.
A COLUMN entry: you will obtain a count of appearances of that particular elementary item.
Assuming that you do not use the RESET phrase, when your COUNT field has been output the count returns to zero. Hence, you will always obtain the count of the number of appearances of the item since the last time the count was output.
You may use the RESET ON phrase to delay the resetting of the count to zero until a higher-level control break occurs, in exactly the same way as you can with the SUM clause.
If the item counted is one that repeats several times because of an OCCURS or REPEATED clause, the count will include each repetition. An OCCURS ... DEPENDING will count just the number of items actually output. A PRESENT clause (or the equivalent) is also taken into account, so that items "not present" do not contribute to the count.
You may count more than one item by writing more than one data-name as an operand in the clause. The counts are then simply consolidated internally.
(The COUNT clause is really a special variant of the SUM clause, so other points of interest can be found under SUM Clause.)
FUNCTION Clause: Coding Rules
Function-name must be alphanumeric and must be either a standard supplied function name or a user-written one. It may begin with a numeric character. A full list of standard function names is given below, and you or any other person may add new ones to the list at any time.
The FUNCTION clause may be used only at the elementary level, in place of SOURCE, SUM, or VALUE. It is permissible for the entry to have no COLUMN or PICTURE clause, i.e. the entry may be a dummy. You may use it in a multiple-choice entry, if so desired.
The number of parameters you need, if any, and their formats are stated below (see 3.7.4) for each built-in function. User-written functions should also have a description that tells you this information. Some functions take no parameters while others allow either a fixed or a variable number.
Each parameter may be any identifier. It may also be an integer, literal, or arithmetic expression, for example:
in which case the parameter is given to the Function routine as a one-word signed binary field. You cannot use SUM or COUNT terms in the expression. Neither can you use LENGTH OF, ADDRESS OF, BY CONTENT, or BY REFERENCE, as part of a parameter.
The FUNCTION keyword may also be used in the format FUNCTION IS function-name (...) in a SOURCE clause or in a condition in a PRESENT WHEN clause. In such cases function-name is a COBOL intrinsic function and is not part of the FUNCTION clause described here.
If you code an edited PICTURE (numeric or alphanumeric) with the FUNCTION clause, report writer invokes the function routine using an internal intermediate field that has the unedited equivalent of your PICTURE. This is obtained by removing all insertion characters, including any decimal point. Also any "Z" or "*" symbol or floating sign or currency symbols are converted to an equivalent number of "9" symbols. The "<" symbol is also removed. For example, if your entry is as follows:
Report writer will provide the function routine with an intermediate field with a PICTURE of 9999V99 as a parameter for receiving the output value. Report writer then executes a MOVE from the intermediate field to your original report field. This means that all functions, including user-written ones, can operate with edited report fields, without function routine developers needing to allow for the many possible edited formats.
One of the parameters report writer passes to the function routine is the size in bytes of the report field, if any, to be output. If the PICTURE is edited, this size is the size of
the intermediate field. Using the case given in the previous paragraph, for instance, the function routine will be told that the size is 6. The Function
routine may decide to produce different formats for the output report field, depending on the number of bytes implied by this size. It may also simply truncate the output value (on the left
or the right) down to the number of characters required. This can give you freedom to choose from many possible PICTUREs to use with a function. For example, if DATE is used, and today's
date is 5th January, 1997:
PICTURE 99/99/99 will give you:
PICTURE 99BXXXB9(4) will give you:
PICTURE <99BX(9)B<9999 will give you:
Functions cannot detect the kind of PICTURE symbols used. For example PICTURE XXBXXBXX produces the same result as PICTURE 99B99B99.
Number of parameters: 0 or 1.
If no parameter is supplied, the date will be the current date at the start of the run. If one parameter is supplied, it must be either a 7-digit
date held in a PIC S9(7) COMP-3 (packed) format in the form ccyyddds (s = sign), or a 5-digit date held in a PIC S9(5) COMP-3
(packed) format in the form yyddds (in which case the current century is assumed).
DAY (Day-of-Week) returns the alphabetic day-of-the-week represented by the given date.
Number of parameters: 0 or 1.
If no parameter supplied, the current date is used. If one parameter is supplied, it may be either a 7-digit date held in a
PIC S9(7) COMP-3 (packed) format in the form ccyyddds (s = sign), or a 5-digit date held in a PIC S9(5) COMP-3 (packed) format
in the form yyddds (when the current century is assumed), or a two- or four-byte (PIC S9(9) COMP or PIC S9(4) COMP) location containing a value from 1 (= Monday) to 7 (= Sunday),
or a one-byte (PIC 9 DISPLAY) location containing a value from 1 to 7.
DAYSIN (Days Elapsed Since Base Date) converts a binary number of days since the base date (see below) to a date in the same format as for DATE.
Number of parameters: 1.
The parameter must be the number of days since the base date inclusive, held as one fullword binary (such as PIC S9(9) COMP). The base date is January 1st 1601, i.e. 584,693 days since absolute year zero (ignoring calendar reforms). A zero value means December 31 1600. A negative value gives a date before December 31 1600. You may change the base date by re-compiling the source of the FUNCTION supplied with this product, in which case your new function should have a different name to avoid incompatibility.
MDAYS (Days Elapsed - US Format) converts a binary number of days since the base date, as defined under DAYSIN above, to a date in the same format as MDATE, that is, month/day/year. This function is otherwise identical to DAYSIN. See MDATE above for more information on report field lengths.
Number of parameters: 0 or 1
If no parameter is supplied, the current month is returned. If a parameter is supplied, it should be either a 7-digit date held in a PIC S9(7)
COMP-3 (packed) format in the form ccyyddds (s = sign), or a 5-digit date held in a PIC S9(5) COMP-3 (packed) format in the form
yyddds (when the current century is assumed), or a two-byte (PIC 99 DISPLAY) location containing a value from 01 to 12, or a four-byte binary (PIC S9(9) COMP) location containing
a value from 1 to 12.
MOVE (Save Register) copies any report writer special register to a specified working location. This is a dummy function which requires no report field and may be coded without a COLUMN or PICTURE clause. (If the entry is not a dummy, the field will be space-filled.)
Number of parameters: 2.
Parameter 1 is any numeric special register, typically LINE-COUNTER or COLUMN-COUNTER. It may also be a user-defined data-name specified in a VARYING clause.
Parameter 2 is any half-word binary location (PIC S9(4) COMP) to receive the contents of parameter 1.
This FUNCTION is used to capture on the fly the contents of a register whose value is constantly changing. The following sample code prints up to 12 monthly payments to print side-by-side showing only those which are not zero and, by storing each value of the VARYING subscript R-MONTH in LAST-MONTH for those occurrences selected, it is able to state which month was the last to be printed.
RYDATE (Real YDATE) is similar to YDATE (see below) without the optional parameter, except that the current date is always fetched. Compare RMDATE.
Number of parameters: 1
The parameter may be either a state number with PICTURE 99 (DISPLAY) ranging from 01 (ALABAMA) to 51 (WYOMING), in alphabetical order of their full names, or a two-character standard abbreviation e.g. "AL" or "WY".
The report-field length must be at least 14. If it is less than 20, then DISTRICT OF COLUMBIA is rendered as D.C.
Number of parameters: none
YDATE (Date Reversed) returns a date in any one of a number of display formats in the order year/month/day. Apart from this order, it is similar to DATE and MDATE.
Number of parameters: 1.
The single parameter must contain the ZIP code in the format S9(9) COMP-3. This is then output in the form nnnnn-nnnn, but the final -nnnn is left blank
if the last four digits are 9999.
GROUP LIMIT Clause: Coding Rules
Your integer must not be greater than the lower limit (LAST DETAIL, LAST CONTROL FOOTING, or PAGE LIMIT) that would normally apply without the clause (see PAGE LIMIT Clauses ).
Code this clause only at the 01-level in a body group (DETAIL or CH/CF).
Your group's first LINE clause must be relative.
This clause is especially useful in a CONTROL HEADING, which might appear misplaced if it appeared near the bottom of the page like the DETAIL and CONTROL FOOTING groups.
JUSTIFIED Clause: Coding Rules
If you code JUSTIFIED RIGHT in an elementary entry, the entry must have an alphanumeric PICTURE.
This clause acts on elementary-level fields, but you may also code it in a group-level entry, including 01, where it applies to all the alphanumeric elementary entries in the group.
The JUSTIFIED clause takes effect when your alphanumeric SOURCE field is of a different size from the PICTURE. The padding out with spaces or the truncation (if the PICTURE is smaller than the field) then takes place on the left instead of the right. In the following example, we want to output either MONTH-NUMBER (2 characters) in columns 12 and 13 or YEAR-NUMBER (4 characters) in columns 10 through 13:
The LINE clause positions a line vertically on the page.
LINE + integer-1. This is the relative form. PLUS may be written in place of +. It indicates that the line should advance integer lines from the previous position. LINE + 0 or LINE + ZERO is allowed, indicating that no advance is to take place. The result is that the line overprints the previous line. You may write "+" with or without a space on either side.
LINE integer-2. This is the absolute form. It indicates that the line will appear on that fixed position on the page. The first line on the logical page is LINE 1, corresponding to position reached on issuing a form feed. The highest line number allowed is given by the PAGE LIMIT operand. This absolute form is allowed only if you have a PAGE LIMIT clause in your RD.
LINE integer-2 ON NEXT PAGE. This is similar to format b but the ON NEXT PAGE phrase forces a page advance to occur before the line is output, irrespective of whether the group containing it would fit on the current page.
LINE ON NEXT PAGE forces the line to be output in the FIRST DETAIL position on the next page (for a body group) or the HEADING position (for a REPORT HEADING or REPORT FOOTING group).
LINES ARE integer-1 integer-2 ... is the multiple form of the clause. It enables you to save coding effort by describing several lines in the same clause. You may also write LINES + integer, + integer etc (the relative form) and may combine both forms in the same clause. You may also write ON NEXT PAGE after the last operand, in which case this phrase applies to the first line in the set.
LINE alone is shorthand for LINE + 1.
The first LINE clause in each group determines whether the group as a whole is to be relative or absolute. If the first LINE clause
is relative, the group is a relative group and all the other LINE clauses must be relative. So the entire group can be positioned anywhere
on the page, within the permitted upper and lower limits for the group:
If the first LINE clause is absolute, the group is an absolute group and any of the remaining LINE clauses may be absolute or relative . For example, the following two arrangements of LINE clauses within a group are equivalent:
Using relative lines has the advantage that you can adjust the position of the entire group by changing just the first LINE number.
If a group has absolute LINE clauses, except where NEXT PAGE is used, the integers must be in increasing order. Except in the case of LINE + 0, no lines may overlap. (If you place PRESENT WHEN condition clauses on the LINE entries, then mutually exclusive lines may have the same line numbers. See PRESENT WHEN Clause.)
A LINE need not contain any COLUMN entries (whether actual or implied by default). The result is a blank line containing no data. For example:
This causes the PAGE HEADING to occupy lines 2 to 4, although data is written only on line 2.
One LINE clause must not be subordinate to another LINE clause. If this rule is broken, a warning message will be issued and the previous line will be terminated; for example:
The ON NEXT PAGE phrase may be coded only in the first LINE clause of a report group, except when the report group entry has a MULTIPLE PAGE clause (or when this is assumed, as in the case of REPORT HEADING and REPORT FOOTING) where there is no restriction. (See MULTIPLE PAGE Clause.) This permits such groups to occupy several pages.
Positioning of relative body groups (CH, DE, and CF)
If the group is the first body group on the page, the first line of the group is positioned at the FIRST DETAIL position, irrespective of the integer of the LINE clause. If you did not code a FIRST DETAIL sub-clause in your RD, the first line will appear one line after the PAGE HEADING group, if there is one, or at the HEADING position if not. Subsequent lines in the group are positioned relative to each other.
If the group is not the first body group on the page, then the first line of the group is positioned relative to LINE-COUNTER, which normally contains the last line position
of the preceding body group. (But note that a NEXT GROUP clause or an alteration to the value of LINE-COUNTER in the PROCEDURE DIVISION can affect this positioning.)
Absolute Page-Fit Test for Body Groups
If the first LINE is absolute, report writer takes the first LINE number as the starting position of the group. (If any of the absolute LINE clauses are
conditional, then this "first line" need not be the first LINE number coded; if all absolute lines are ABSENT, the group will be treated as null or relative, as the case may be.)
If LINE-COUNTER is positioned at a line above the starting line position of the group, report writer will not skip to a new page. In all other cases, a page
advance takes place (see item 5 below) and the group is printed at the line specified on a fresh page. The next diagram illustrates this process:
Relative Page-Fit Test for Body Groups
When all the LINE clauses in the group are relative, report writer computes the total of all the integers of the LINE + clauses. This gives the total size of the group. If the group contains LINE entries that have a condition attached, as from a PRESENT WHEN/AFTER clause, or from an OCCURS ... DEPENDING clause, all these clauses are evaluated first, so that the actual number of lines about to be produced is known. The value LINE-COUNTER + total-size-of-group is the last line on which the group would appear if it were produced on the current page. If this last line position is beyond the lower permitted limit of the group, the group cannot fit on the page and a page advance takes place.
As shown by the diagram and rules under PAGE LIMIT Clause, and GROUP LIMIT Clause, the lower permitted limit of the group is given by:
¶ The report group's own GROUP LIMIT clause, if there is one, or
¶ The RD's LAST DETAIL, if the group is a DETAIL or CONTROL HEADING
¶ The RD's LAST CONTROL FOOTING if the group is a CONTROL FOOTING.
The LAST DETAIL and LAST CONTROL FOOTING sub-clauses need not be explicitly specified in your RD, as report writer will assume defaults for them, as outlined under PAGE LIMIT Clause (see 2.9.3 (7)).
The following diagram shows an example of a page-fit test.
Positioning of relative non-body groups (RH, PH, PF, and RF)
TYPE RH and PH: relative to HEADING minus 1. (However, in the case of the first PH group when there is a RH group also on the first page, it is relative to the last line of the RH group.)
TYPE PF: relative to LAST CONTROL FOOTING.
TYPE RF: relative to HEADING minus 1. (However, in the case where the RF group does not begin on a new page, it is relative to the last line of the PF group, if there is one, or to LAST CONTROL FOOTING, if there is no PF group.)
Page advance processing
When report writer executes a page advance, it does the following:
¶ If you defined a PAGE FOOTING, this is output.
¶ PAGE-COUNTER is incremented by 1.
¶ An advance is made to the top of the next page. In "batch" printing a form feed is output, but with an Independent Report File Handler the action may vary (see 5.3). LINE-COUNTER is then set to zero.
¶ If you defined a PAGE HEADING, this is output.
A multiple LINES clause is functionally equivalent to a LINE with an OCCURS clause; for example:
You may use a VARYING clause to vary an internal counter that may be used as a subscript in a SOURCE clause within the scope of the LINE clause.
A simple (single-operand) VALUE, SOURCE, SUM, or FUNCTION is repeated in every occurrence of the line.
You may use a multiple VALUE or SOURCE clause to place a different value in a report field in each occurrence of the multiple LINE.
You may place a data-name at the start of the entry and SUM it into another entry to produce a total of all the (multiple) entries.
However, in contrast to the OCCURS clause, the intervals between the lines defined by a multiple LINES clause need not be regular.
Your multiple LINES clause will be syntactically correct if it would be correct when written as a series of LINE clauses in separate entries.
Here are some examples of the multiple LINES clause:
Here the ON NEXT PAGE phrase applies to the first of the three lines:
The multiple LINES clause is useful in lines, such as headings, that have stacked text. Consider the following example in conjunction with the description under Multiple SOURCES and Multiple VALUES:
It may be coded as follows:
You need not code the multiple VALUES in a "stacked" format like this, but it is suggested to aid readability.
Uses of LINE-COUNTER
LINE-COUNTER is a special register giving the current vertical position on the page. After a GENERATE has been executed, LINE-COUNTER will be set to the line number of the last line occupied by the last group output. A NEXT GROUP may change it further (see NEXT GROUP Clause). You can test the value of LINE-COUNTER to determine the vertical position on the current page.
Whenever you issue a GENERATE, report writer examines LINE-COUNTER to decide where it should output the lines of the group. It is set to zero by the INITIATE and by a page advance. Then, if your line has a LINE + integer clause, report writer uses (LINE-COUNTER + integer) as its target line. When the page-fit test is performed for a relative body group, report writer adds the size of your group to LINE-COUNTER to see whether the last line will be below the group's lower limit.
You may alter the value of LINE-COUNTER in the PROCEDURE DIVISION, but take care! Do not reduce the value of LINE-COUNTER, or you are liable to cause too many lines to be written to your page so that it overflows its lower limit. You may increase its value safely. Some legitimate reasons for altering its value are:
To create an additional gap between the previous group and the next group:
If your page is nearly full (so that LINE-COUNTER is nearly equal to the LAST DETAIL value) this will simply cause a page advance upon the next GENERATE instead of a gap. If your ADD statement sets LINE-COUNTER below LAST DETAIL, no harm is done. You should note that the NEXT GROUP clause performs this function more elegantly.
To cause a page advance, that is, to force report writer to place no more body groups on this page, code:
Again, coding the NEXT GROUP NEXT PAGE clause on the previous group also performs this function better. (See NEXT GROUP Clause.)
If your REPORT SECTION has several Report Descriptions, each will have its own distinct LINE-COUNTER. In the main-line PROCEDURE DIVISION, you will
therefore need to qualify LINE-COUNTER by the name of the report. (See PAGE-COUNTER, and Multiple Reports.)
MULTIPLE PAGE Clause: Coding Rules
This clause can be coded in any type of group other than PAGE HEADING and PAGE FOOTING. The RD must have a PAGE LIMIT clause.
Either MULTIPLE PAGE or NO MULTIPLE PAGE may be coded at the 01 level. Alternatively, NO MULTIPLE PAGE may be coded on a group of one or more LINE entries, provided that there is a MULTIPLE PAGE at the 01 level. No other nesting is allowed.
By default, NO MULTIPLE PAGE is assumed for all body groups and MULTIPLE PAGE for REPORT HEADING and REPORT FOOTING groups.
The MULTIPLE PAGE clause is not allowed in a group that has a REPEATED clause.
When the group is a body group with MULTIPLE PAGE, no page fit-test is performed for the group as a whole. Instead, each report line is subjected to an individual page-fit test. A LINE clause with NEXT PAGE also causes a page advance to take place. Loosely speaking then, a multiple page group may begin at any point and cause a page advance at any point.
When a page advance is required, a PAGE FOOTING and PAGE HEADING group are printed as usual if defined. This is the only case where groups may interrupt another group.
If the line that caused the page advance is relative, it is placed in the FIRST DETAIL position, disregarding the integer of its LINE clause. In the following layout, note how the
"ROBINSON" group (in blue if you have color) spans three pages:
NO MULTIPLE PAGE can be used to prevent the lines in its scope from being split over a page boundary. If an OCCURS clause is also present, this rule applies separately to each occurrence. In the following example we want each set of address lines to remain together on the page:
At the 01 level, NO MULTIPLE PAGE merely documents the usual situation that a group cannot span pages.
NEXT GROUP Clause: Coding Rules
This clause must be written only at the 01-level.
You can use the clause in any body group (DETAIL or CH/CF) and also in a REPORT HEADING (provided that a PAGE HEADING is present) as well as in a PAGE FOOTING (provided that a REPORT FOOTING is present).
If your report has no PAGE LIMIT clause, you can use only the + integer-1 form.
The optional words BODY and DE OR CH document the effect of the NEXT GROUP clause in the context of the type of group in which it is coded, but they do not have any actual effect on the clause. You can write NEXT BODY GROUP only in a DETAIL or CONTROL HEADING group, and NEXT DE OR CH GROUP only in a CONTROL FOOTING group.
DE OR CH may also be written: DETAIL OR CONTROL HEADING, CH OR DE, or CONTROL HEADING OR DETAIL.
If you write NEXT GROUP + integer-1, report writer will add integer-1 to LINE-COUNTER, but using the LAST CONTROL FOOTING value as a maximum limit.
This creates an extra "gap" of that many lines between this group and the next, provided that there is room for both to appear on the same page. The following diagram shows how to
use the clause to create more space after a CONTROL FOOTING:
Notice that there is no "gap" after the TOTAL GEORGIA group, because it already extends to the LAST CONTROL FOOTING position.
You might suppose that you could also get extra blank lines by writing a blank LINE entry (containing no COLUMN entries or just a VALUE of SPACES) at the end of the group. But this is not a satisfactory replacement for the NEXT GROUP clause, because the blank LINE is treated as a part of the group and will affect the page-fit test. For example, if you had written
at the end of the CF group instead of the NEXT GROUP clause in the above example, the TOTAL GEORGIA group would have appeared at the top of the next page, because its total depth would now be 5 lines instead of 3. Likewise, a LINE + 2 at the front of the DETAIL group would produce unwanted blank lines ahead of every DETAIL group.
The NEXT GROUP integer-2 (absolute) form may force the next body group to be produced relative to the given line number. Report writer first examines the LINE-COUNTER. If this is less than integer-2 (in other words, if that position has not yet been reached), LINE-COUNTER is set equal to integer-2. Otherwise, report writer sets LINE-COUNTER equal to LAST CONTROL FOOTING to ensure that no more body groups will appear on this page and saves the value of integer-2 in the Saved Next Group Integer location. Before the next body group, if any, is produced, report writer sets LINE-COUNTER equal to the saved integer. It is inadvisable to use this form of the clause unless your next body group will always be a relative group.
If you write NEXT GROUP NEXT PAGE, report writer will set LINE-COUNTER to the LAST CONTROL FOOTING value. This forces report writer to leave the rest of the page blank and begin the next body group, if any, on the next page. (LAST CONTROL FOOTING is the lowest position on which any body group can appear as described under PAGE LIMIT Clause).
To begin on a fresh page after a control break, you may place NEXT GROUP NEXT PAGE in the CONTROL FOOTING for that control level, as the following example shows:
If you write a NEXT GROUP clause in a CONTROL FOOTING group, report writer checks the level of the control break being processed before putting the clause into effect. If the level of the break is higher than the level of this group, the NEXT GROUP clause is ignored. This means that a CONTROL FOOTING's NEXT GROUP clause can never affect the position of the next CONTROL FOOTING. As the following example shows, the CONTROL FOOTING FOR REPORT (the grand total) will not be forced onto a new page. To document this fact, the optional words DE OR CH are provided in the syntax.
If you should want the CONTROL FOOTING FOR REPORT to appear on a new page in this case, you should instead code ON NEXT PAGE in its first LINE clause.
You can code a dummy report group containing only a NEXT GROUP clause, as in the example below. When the group is processed, no output takes place, but LINE-COUNTER will be set equal to LAST CONTROL FOOTING solely because of the NEXT GROUP NEXT PAGE clause. This may be useful when you want to begin a new page on change of, say, BRANCH, but there is no subtotal that would normally justify coding a CONTROL FOOTING group. Just write:
To obtain a gap of three lines at any time, as an alternative to altering LINE-COUNTER directly, code:
and in your Procedure Division, write: GENERATE THREE-LINE-GAP.
You can also write NEXT GROUP in a PAGE FOOTING group, in which case it affects the REPORT FOOTING. This form is never necessary, as the first LINE
clause used in the REPORT FOOTING is a better way to handle this case.
OCCURS Clause: Coding Rules
The OCCURS clause must not be used at the 01-level.
You may use the OCCURS clause at any of these levels:
Below the LINE level in an elementary entry. Your field will be repeated horizontally the number of times indicated by the operand:
Below the LINE level in a group entry. The whole group of fields will be repeated horizontally the number of times indicated by the operand.
At the LINE level. The line will be repeated vertically the number of times indicated by the operand.
Below the 01-level but above the LINE level. The whole group of lines will be repeated vertically the number of times indicated by the operand.
These four levels are known as axes. Any fields in your group can be repeated in this way on any of the four axes, and you may have repetition on up to four axes by nesting the OCCURS clauses. Each of your report groups may have any number of OCCURS clauses, provided that the nesting limit of four is never exceeded at any one time.
You may use STEP, WIDTH, or DEPTH to specify the distance between the start of successive repetitions. Its operand indicates the number of columns or lines between the start of one item and the start of its successor:
Integer-3 of the STEP phrase must be at least as large as the field itself. WIDTH and DEPTH are alternative keywords with the same meaning as STEP. WIDTH may be used only in the horizontal direction and DEPTH may be used only in the vertical direction. You can write the documentary words COLUMNS or LINES after integer-3 to make the direction explicit. The STEP, WIDTH, or DEPTH phrase may be coded anywhere within the entry.
A STEP phrase is expected if your repeating entry is absolute. (It is absolute if you write COLUMN integer or LINE integer or, in the case of a group field, if the first COLUMN or LINE in the group is absolute.) However, if you omit STEP, a minimum value will be assumed, equal to the (maximum) size of the report field, with a cautionary message.
If your field is relative, the STEP phrase is optional. If you omit it the distance between repetitions is the physical size of the field, which may vary at run time if there are "<" PICTURE symbols or if the field is a group field containing entries with a PRESENT WHEN clause.
As the examples above illustrate (see 2a - 2d), the VALUE clause is allowed within a entry subject to an OCCURS clause.
You must code the DEPENDING ON phrase if the number of occurrences is variable. The expression can be any COBOL numeric identifier or arithmetic expression that has an integer value. The data items used in your expression can come from anywhere in your program. They need not appear elsewhere as report fields and need not reside in the same "record" as the SOURCE fields.
Integer-1 in the format above and the TO keyword are used only in conjunction with DEPENDING ON. Integer-1 must be less than integer-2 and may be zero. If you omit integer-1 TO and write OCCURS integer-2 TIMES DEPENDING ON, this is taken to mean OCCURS 0 TO integer-2 TIMES DEPENDING ON.
You may use a single-operand VALUE to place the same contents in each repetition.
If you use a SOURCE clause within an entry subject to OCCURS, the same SOURCE operand will be used to set up each occurrence. However, you may allow the effective SOURCE operand to vary by use of the VARYING clause and making use of the VARYING data-name as its subscript or as a term in the SOURCE operand. (See VARYING Clause for full details and examples.)
You may also use a multiple SOURCES (see 3.21) or multiple VALUES (see 3.26.4) to place different contents in each repetition. The following
sample layout shows both methods of combining both SOURCE and VALUE clauses with OCCURS:
which may be coded as follows:
Notice how the series of row-heading items (NORTH, EAST, etc.) is handled: the enclosing OCCURS at the LINE level simply steps through each item in the series in turn.
The effect is similar in the horizontal direction:
However, if a STEP phrase is used, the spacing - in whichever direction - is regular and even entries that are ABSENT take up their usual space:
which may be coded as follows:
Use of OCCURS...DEPENDING ON
If your report group has an OCCURS clause with a DEPENDING ON phrase, report writer will evaluate the associated identifier or expression at run time on each separate occasion when the report group is about to be generated. If its value is outside the range of integer-1 TO integer-2 in your OCCURS clause, this is not an error condition, and report writer will assume the maximum number, integer-2.
Now that the actual number of repeats is known, report writer creates only that number of occurrences, treating your clause as though you had written a fixed OCCURS clause with that number as the integer. This is an important notion. Here are some of its consequences:
If your OCCURS ... DEPENDING is in the horizontal direction and is followed by an absolute COLUMN clause, the space not filled by excess occurrences will be blank:
If COUNT-1 contains 3, the effect is as though you had written:
If your OCCURS ... DEPENDING is in the horizontal direction and is followed by a relative COLUMN, it is positioned relative to the last actual occurrence:
If A + B equals 3, the result is as though you had written:
If your OCCURS ... DEPENDING is in the vertical direction and is followed by an absolute LINE, excess occurrences will be blank:
If COUNT-1 contains 2, the result is as though your OCCURS 1 TO 4 clause above were simply coded as OCCURS 2:
If your OCCURS ... DEPENDING is in the vertical direction and is followed by a relative LINE, no line positions will be occupied by the unused occurrences, and the line that follows will be relative to the last actual occurrence.
The page-fit test allows only for the occurrences that are actually present. So, if the group as a whole is relative, you will have a "best fit". For instance, if you GENERATE the above group and only three lines are available to it, the group will fit on the page.
You may code several entries with OCCURS ... DEPENDING in the same report line and nest horizontal and vertical repetitions to produce many varied and useful effects. The DEPENDING expression is re-evaluated each time the item is about to be output, so you may alter the size and shape of your report fields dynamically and automatically. You may also use OCCURS ... DEPENDING in a horizontal or vertical group entry.
Uses of PAGE-COUNTER
PAGE-COUNTER contains the number of the current page. It is set to 1 by the INITIATE statement and, if your report has a PAGE LIMIT clause, is incremented by 1 on each page advance after the initial one. So its value is 1 on the first page, 2 on the second, and so on. The incrementing takes place between the production of your PAGE FOOTING group, if you defined one, and your PAGE HEADING group, if you defined one. So accessing PAGE-COUNTER in a USE BEFORE REPORTING Declarative section for a PAGE HEADING, for example, yields the value that applies to the new page. The TERMINATE statement leaves PAGE-COUNTER unchanged.
You may treat PAGE-COUNTER as a numeric location (implicit PICTURE S9(9) COMP SYNC) in any SOURCE expression or condition. For example, to print the page number anywhere in the page, write:
You can change the value of PAGE-COUNTER at any time. Just treat it as any numeric data item (except that report writer defines it automatically). As an example, if you want to restart your page numbering from 1, after each control break, code
in a Declarative SECTION for the CONTROL HEADING, so that when report writer next does a page advance it will increment it from zero to one.
Like all of the special registers except COLUMN-COUNTER, a PAGE-COUNTER is maintained separately for each report, because all your reports are completely independent of each other. This also means that you must occasionally qualify PAGE-COUNTER if you have more than one report in the program. You do this by using report-name as a qualifier, as shown in the format at the head of this section.
You need a qualifier only if there is ambiguity, that is, in the main-line PROCEDURE DIVISION. In the Report Group Descriptions and in a USE BEFORE REPORTING section report writer assumes that you mean "IN current-report". However, you may still use a qualifier even in those cases, for instance when you want to access the PAGE-COUNTER of a different report. More information on multiple reports will be found in 5.1.
PICTURE Clause: Coding Rules
All the available PICTURE symbols may be used, including a currency symbol defined by a CURRENCY SIGN phrase, provided they are consistent with a DISPLAY field, and the rules for combining them are exactly as for basic COBOL. Here are some examples:
If the item is DBCS (Double-Byte Character Set), the PICTURE may contain only the symbols G and B (representing a DBCS space). However, a PICTURE clause is not required with a DBCS literal.
Report writer allows the additional left-shift PICTURE symbols "<" and ">" to indicate that all or part of your field is variable-length . These symbols may be used only in the REPORT SECTION. You may place the "<" symbol anywhere within the PICTURE, in any number of places, provided that it is followed by one of the following symbols: "X", "A", "9", "Z", or floating (that is, repeated) "-". (In other words, it must appear before a symbol that represents "data", as opposed to an "editing" symbol.) The ">" symbol may optionally be used to terminate its scope. The effect of these symbols is described below (see 3.16.4).
Report writer also allows general insertion characters, in the REPORT SECTION only. These are indicated by writing the characters to be inserted in "quotes" (or 'apostrophes') anywhere in the PICTURE, for example: PIC 99"."99"."99. These insertion characters do not take a repetition factor (so that PIC "."(5)X is invalid and must be written PIC "....."X).
You may omit the PICTURE clause in an entry that has a VALUE clause, whether nonnumeric (when a PICTURE X(n) is assumed) or (unsigned) numeric (when a PICTURE S9(n) DISPLAY is assumed.) (A SYMBOLIC CHARACTER is treated as a one byte nonnumeric.) A PICTURE is required if you use ALL "literal", or a figurative constant such as QUOTE. In the case of a multiple VALUE or multiple-choice entry, there may be several "literals" but still no PICTURE is required.
If you use a SOURCE, SUM/COUNT, or FUNCTION clause, the PICTURE is necessary, even if you want to display the field in exactly the same format in which it is stored.
If the precompiler option is in effect, PICTURE symbol "A" may be used even with a literal that is not entirely alphabetic.
In common with the rest of the DATA DIVISION, PICTURE is allowed only in an elementary entry.
General insertion characters may used to reduce the number of entries to be coded. For example:
may be reduced to:
may be reduced to:
may be reduced to:
Note that an insertion character specified in this way never has any semantic significance. Thus "." is never treated as a decimal point for alignment purposes.
Report writer will divide the field into the following parts:
9 (1 character fixed)
<99 (0 to 2 characters variable)
,999. (all fixed)
<99 (0 to 2 characters variable)
The variable parts of your field are represented by those parts of your PICTURE that follow a "<" symbol, up to a change of symbol. To mark where each variable part ends, you may code a ">" symbol, resulting, in the above case, in:
By convention, PIC <Z(n) is taken to mean the same as the more conventional PIC <9(n), and PIC <$(n) is understood to mean the same as PIC $<9(n-1).
When your field is output, report writer first stores the value to be output in a working area whose PICTURE is the same as the PICTURE you coded but without the "<" symbol(s) . It then examines each part of your field that corresponds to a variable part of the PICTURE. If the symbol after the "<" is "X" or "A", that part is non-numeric and report writer will delete trailing spaces (that is, it will not advance COLUMN-COUNTER over them). If the symbol after the "<" is "9" or "Z" or "-", that part is numeric and report writer will delete leading zeros by left-shifting the contents of the rest of the field. After a decimal point, either explicit (.) or implicit (V) followed by a "<" symbol, it is trailing zeros that are deleted.
When characters are deleted, any characters that follow them are pulled to the left over them. This gives a free format effect to variable fields that have several parts. When the field has been output, the horizontal pointer (COLUMN-COUNTER), will point to the last character stored. If your next entry has an absolute COLUMN, you will have a variable number of spaces from the end of this field to the fixed starting point of the next. If, however, your next entry has a relative COLUMN (COL +), the number of spaces between the fields will be fixed, but the starting position of the next field will vary.
You may use the "<" and ">" symbols to split any part of your field into two fragments, one variable and one fixed, resulting in a minimum size and a maximum size.
For example: PIC XX<XXX> means from 2 to 5 non-numeric characters; while PIC <999>9 means from 1 to 4 numeric characters
(a form that is more useful than PIC <9(4) because a value of all zeros is reproduced as a zero).
a. If PICTURE -9999.99 gives you the result:
Then PICTURE -9<999.<99 will give you the result:
b. If PICTURE 99/99/99 gives you the result:
Then PICTURE <99/<99/<99 will give you the result:
gives you the result:
gives you the result:
Special action is taken with the "," (comma) and "." (decimal point) symbols. If you write a "<" and a series of "9" symbols before "," and the numeric value that corresponds to them is zero, then the "," will also be deleted. Also, if you write "<" after a "." (decimal point) and all the numeric positions after the decimal point are zero, then the decimal point will also be deleted. For example, if your field is described as:
then values of 00002345.10 and 00000001.00 will be reproduced as:
You may code this clause at the group or elementary level and may nest clauses.
You may use format a in any body group (DETAIL or CH/CF), but, if you use the control-id option in a CONTROL HEADING or CONTROL FOOTING group, the control level you refer to must be higher than the control level of the report group in which the PRESENT AFTER clause is coded.
You may also use format a in a PAGE HEADING or PAGE FOOTING group, but only with the control-id option.
Format b (with the JUST phrase) can be used only in a body group.
Format c, the GROUP INDICATE clause, is provided for compatibility with current standards. Except for one minor but useful difference in its action with
OCCURS (see below), it is equivalent to the clause:
For example, if the RD entry has the format:
If you code PRESENT AFTER NEW control-id, report writer will output the field (elementary or group field), provided that this is the first occasion this report group has been output since the start of the report or since the last control break at the level of control-id or above. For example, if you write PRESENT AFTER NEW BRANCH-NO, your report field will be produced at the beginning of the report and at the first GENERATE after each change of BRANCH-NO (or any higher control). Otherwise, the field is ignored, together with any subordinate entries, in exactly the same manner as with the PRESENT WHEN clause.
In the following example, the field YEAR-NO is to be output the first time only and then whenever it has changed, while SEASON-NO is to be output the first time and then whenever
it or YEAR-NO has changed.
As is usual with controls, a higher control break implies a control break at all the lower levels. Thus if you code PRESENT AFTER MONTH when YEAR and MONTH are the controls, the field will be PRESENT also after a change of YEAR, for JAN 1992 is certainly different from JAN 1991!
If you code PRESENT AFTER NEW PAGE, report writer will produce the entry if this is the first occasion this group has been produced since the start of the report or since the last page advance. Otherwise, again, the field is not output.
As the following example shows, it may cause the entry to be produced at any position within the page provided the group containing it has not yet appeared on the page. If you want the entry to appear only if this group is also the first body group of the page, you should instead use the form: PRESENT JUST AFTER NEW PAGE. In the example that follows, this would prevent the subheading UNFILLED ORDERS from being printed in the body of the page.
In the following example, one group has a subheading for unfilled order details and we want this subheading to appear only the first time that the group is
printed on the page:
If you write PAGE OR control-id (this order can be reversed), the field will be produced if either or both conditions arise. For instance, you might want the YEAR-NO and SEASON fields in the examples above (see item 2) to be printed again at the start of a new page even though there may have been no change. In this case, you must write:
There may be a field, line, etc. that you would like produced the first time only. To accomplish this, use PRESENT AFTER NEW REPORT. (REPORT or FINAL is the highest control level and is always assumed even if not coded in the CONTROL clause.) In the next example, it is in the PAGE HEADING:
To anchor the vertical starting line of this relative group, you may include a HEADING sub-clause in your RD.
If you write ABSENT instead of PRESENT, the clause will have exactly the opposite effect. In other words, the field will be produced whenever it would have been ignored
and vice versa. In the next example, we use it to produce a "(CONTINUED)" message in our PAGE HEADING. It will appear on every page except the first page after
each new control value. (This message is also useful in CONTROL HEADING groups.)
If there is an OCCURS clause, or a multiple LINES or COLUMNS clause, in the same entry, the PRESENT AFTER applies to the entire set of repetitions, so the occurrences are either all present or all absent. (Compare GROUP INDICATE below (see rule 9).)
behaves differently from the equivalent PRESENT AFTER clause if it is subject to OCCURS. As soon as the first occurrence of the GROUP INDICATE
item has been output, the GROUP INDICATE is switched off. Hence the GROUP INDICATE clause only enables one entry to be output (the leftmost of topmost, depending
on the axis), whereas PRESENT AFTER affects each occurrence equally and is switched off only when the whole table has been output. This fact can be put to practical use if you want some text
to appear with the first entry only:
(Note that if you want "ADDRESS:" to be printed again each time ADDRESS-GROUP is GENERATEd you need to ensure that a control break occurs on each GENERATE of ADDRESS-GROUP.) Using GROUP INDICATE in this example is better than coding PRESENT WHEN R-LINE = 1, since the latter will not work here if the first occurrence of ADDR-LINE might contain spaces.
If you use the PRESENT AFTER clause at the 01-level of a DETAIL group:
and you require this group to appear as soon as there is a change to the control BRANCH-NO, your program should GENERATE this group before every other GENERATE for the report. In spite of any appearance to the contrary, you may rest assured that the PRESENT AFTER clause will not make a group appear if your program does not GENERATE it.
Each of the data items you use in your condition may come from any COBOL SECTION (but see the note regarding PRESENT WHEN under 3.23.4 the SUM clause if you use SUM fields from the REPORT SECTION itself). You may optionally place parentheses "( )" around the whole conditional expression for clarity. The symbols ">=" (greater than or equal to) and "<=" (less than or equal to) are allowed. For more information, you should refer to your COBOL language reference (see Related Publications) under conditional expressions, for a list of the many varied ways of forming COBOL conditions.
The CONTROL IS control-id form if allowed only if the current group is a multiple CONTROL FOOTING, that is, one with a TYPE CONTROL FOOTING clause with more than one control-id operand, or TYPE CONTROL FOOTING FOR ALL.
The keyword PRESENT is implied if omitted. Experience has shown that your code will be clearer if you include the PRESENT keyword in the single form of the clause but omit it in the multiple-choice form described below and in the following example:
The keyword ABSENT gives the clause the exact opposite meaning from the same clause with PRESENT; ABSENT WHEN condition is equivalent to PRESENT WHEN NOT (condition). So you may find it more expressive to write:
Whenever we refer to the PRESENT WHEN clause, you can assume that this term includes the ABSENT WHEN form.
PRESENT UNLESS is an older syntax, synonymous with ABSENT WHEN.
You may write these clauses in any report group entry other than the RD itself. An entry that has a PRESENT WHEN clause is often referred to as a conditional entry. The same field may be subject to any number of PRESENT WHEN clauses at any number of different levels. The following sample group has one of the clauses in all the possible positions:
If you nest more than one PRESENT WHEN clause by writing one clause in a higher entry and another in a lower entry beneath it, as in the preceding example, the outer condition takes precedence over the inner condition. It is up to you to ensure that both conditions can be true at the same time. Report writer will not check for contradictory combinations of conditions such as:
Here, if A is not 1, the whole LINE will not be output and that is an end to the matter: the test for A = 2 is short-circuited and the "X" will never be output.
Remember, when the PRESENT WHEN is not on an elementary entry, your masking "card" must be large enough to cover all the lower-level entries, down to elementary level, as far as the next entry at the same level or higher. Now, to find out what will be produced when an entry is ABSENT, just cover the entry with the mask, so that it disappears from view. The remaining entries are what report writer "sees" at that instant, and therefore what it will output. For example, suppose that the field CITY-FLAG is 1 and INS-FLAG is zero in the example above. What will report writer produce? Just move the mask over the INS-FLAG group entry, as shown above, and this is what results:
Keeping this simple principle in mind, consider the practical applications described in the following paragraphs:
To "blank out" a field with an absolute COLUMN, place your PRESENT WHEN on the absolute COLUMN entry and follow it with another absolute COLUMN entry:
If HOUSE-NO-FLAG is not 1, the entry in column 4 disappears. Because the following column is in an absolute position, the first entry is blank:
This method also enables you to blank out an absolute LINE entry from a set of absolute LINE entries, leaving a gap in the printed output.
The word DEBIT displaces the next field to the right because the next field has a relative COLUMN clause (COL +1). Place your "mask card" over the DEBIT entry and you will see what occurs when its group is not produced: the AMOUNT field is the first and only field to be produced, and its COLUMN number is +1. It therefore appears in column 1.
Similarly, the HOUSE-NUMBER field in the previous paragraph could be treated as a conditional insertion item by revising the code as follows. (The "<" symbol eliminates the gap after short HOUSE-NUMBERs.)
This time, if HOUSE-NO-FLAG is not 1, there is no "gap" because the item that follows is relative.
To place one of a series of alternative entries into the same column positions, code several entries, each with a PRESENT WHEN clause.
Take care that the conditions are mutually-exclusive so that none of the fields can overlap:
Notice that the conditional fields need not all start in the same column and that the column numbers need not be strictly in sequence, provided that they are in sequence when we mask out the entries that are ABSENT.
If all your entries start in the same column and are all literals or identifiers with the same PICTURE, you will find it more convenient to use a multiple-choice entry. (See 3.18.5 Multiple-Choice Form, below.)
You can also use the technique shown here to choose one LINE from a set of alternative absolute LINE entries.
The dummy entry specifying COL 14 gives you an anchor point at which to begin. It ensures that the first sport-field will appear in column 16.
If you include many optional fields using relative COLUMNS, you may run the risk of causing line overflow if a large number happen to be present. If you want report writer to "wrap the data round" on to a continuation line, you must code a WRAP clause (see WRAP Clause). Otherwise, it will truncate the line and create a run time line overflow message.
A similar problem might arise if you define an entry in an absolute column following your series of optional entries. If there were too many entries present, report writer might signal a run time column overlap error. If there is a risk of line overflow or column overlap, you must do some extra processing before you GENERATE the line, to make certain that no more than the maximum number of fields will be present.
To print one or more of a series of conditional lines in a report group, use relative LINE clauses and code your PRESENT WHEN clauses at the LINE level
In this example, the lines showing AGE OF SPOUSE and NO. OF CHILDREN are not to be produced unless there is a "family membership" condition, and the line showing GOLF SUBSCRIPTION is not to appear unless the member plays golf. Here is some suitable report writer code:
Because report writer only "sees" the lines that have not been "masked out", it performs a sophisticated page-fit test. Report writer will test the availability of only the number of lines that will actually be output. If THOMPSON in the above example begins on line 59 of a 60-line page, his record will appear on that page because at that particular instant the DETAIL group is actually only 2 lines in depth.
The form CONTROL IS control-id is a special condition that can be used only in a PRESENT WHEN clause within a multiple CONTROL FOOTING. It is true if the level of the CONTROL FOOTING currently being generated is that of control-id. For example, if the TYPE clause is:
you may introduce any amount of variation for each level by coding, for instance:
If PRESENT WHEN is used in the same entry as an OCCURS clause or a multiple SOURCES or VALUES, the PRESENT WHEN applies to each occurrence individually.
Only those SUM operands that were PRESENT when they were processed will be added to a total field. An item will not be added if it is subject to a PRESENT WHEN and the condition is false. This means that you may total a series of "optional" fields and obtain a total that is true in the sense that only the fields that are processed appear in the total field. (The word processed includes the case of unprintable fields - those having no COLUMN clause - which do not appear in the report.)
The following example illustrates this principle:
If you write a SUM clause and a PRESENT WHEN together in the same entry, the total will not appear in the report if the entry is not present . But neither will it be cleared to zero, because no total is cleared until it has been output. Values will continue to be accumulated in the total field even though the SUM entry may not always be present. In other words, the PRESENT WHEN in the SUM entry can delay the generating and clearing of your total field but it has no effect on the totalling itself.
These facts may be utilized if you wish to generate a number of fields repeatedly but delay the appearance of their cross-foot total. In the following example, we have
a variable number (up to 31) of fields, but only up to five will fit on a line. The total also occupies a field in the line. The following solution takes advantage of
the fact that if a DEPENDING ON operand is higher than the maximum, the maximum (in this case 5) is assumed. (This problem can also be resolved now using the WRAP
To accumulate a series of totals split up by some category, that is into separate "pigeonholes" or "buckets", you may use a series of unprintable SUM fields partitioned by a series of mutually exclusive (and exhaustive) PRESENT WHEN condition clauses. Suppose that you wish to print "Sales of Ice Cream" and you want to total separately the sales of Vanilla, Strawberry and Chocolate flavors.
This is done by splitting up the sales entry invisibly into vanilla, strawberry and chocolate sales, as though we were actually splitting
it thus at the place where it is printed. We then SUM each unprintable entry to form three separate totals:
If you have a larger, or variable, number of categories, it will be easier to defined repeating values and totals using OCCURS. Suppose that the flavors VANILLA, STRAWBERRY etc. are held in a table W-FLAVOR OCCURS 20. The following code could now replace the corresponding entries used above:
The Multiple-Choice Form
If you need to specify a series of alternative contents for a particular elementary field, you can do it with a single entry, instead of several separate entries containing PRESENT WHEN clauses. You code the entry with several SOURCE, VALUE, or FUNCTION clauses, each followed immediately by a PRESENT WHEN clause. One of the PRESENT WHEN clauses, and only one, may be of the form PRESENT WHEN OTHER. It is normally placed last in the list (although this is not syntactically required).
Report writer scans your WHEN conditions, starting with the first in the order of coding, until it finds a condition that is true. It then uses the SOURCE, VALUE, or FUNCTION clause preceding that PRESENT WHEN clause and ignores all the remaining PRESENT WHEN and SOURCE, VALUE or FUNCTION clauses. So your conditions need not be mutually exclusive: the testing is on a "first-come-first-served" basis. Here is an example:
The contents of TAX will be produced when TYP-IND is between "B" and "Z" inclusive.
If your conditions do not cover all the possibilities, you have three choices:
Put WHEN OTHER instead of WHEN condition against the entry you would like to act as the catch-all, default, or wastebasket :
Code an extra "choice" using WHEN OTHER to indicate an error:
Leave it as it is. If there is a case not covered by your multiple-choice entry, the whole field will then simply be ABSENT. For example:
If SMITH has TITLE-CODE equal to 0, this will result in:
If you specify only VALUE literal clauses without a PICTURE clause, they may be of different sizes, as in the preceding example. The actual size of the field
produced will be that of the chosen value. Since SURNAME above has a relative COLUMN, you will obtain:
You can form a SUM of a multiple-choice entry. Report writer will select the correct choice (if any) before adding it to the total:
This adds only the one correct choice each time.
You can use the CONTROL IS control-id form of condition anywhere in a multiple-choice entry. For example:
You can use multiple SOURCE and VALUE clauses within your multiple-choice entry. For example:
You cannot place a multiple-choice entry at the same level as a LINE clause. The construct:
is therefore illegal and must be replaced by:
The REPEATED clause arranges body groups side-by-side across the page.
REPEATED Clause: Coding Rules
Write this clause at the 01-level of body groups (DETAIL or CH/CF) only.
You must code either the TIMES phrase or the EVERY/WIDTH phrase, or (preferably) both. EVERY and WIDTH have the same meaning.
Code only the left-hand report group. Report writer will automatically offset successive groups to the right of the left-hand group.
If you use the EVERY/WIDTH phrase, draw an imaginary "smallest box" around your group:
The width of your box must not be greater than the EVERY/WIDTH integer-2. If any of your lines can have a variable rightmost column position, you must use the maximum expected size while drawing your box, but report writer cannot always predict the actual size at precompilation time. If the actual width of the group then causes it to encroach into the area occupied by the group to its right, a run time error will be issued.
There are no other restrictions on the size of your group or the clauses that you can use within it. For example, you may specify any number of LINES.
If you omit the TIMES phrase, report writer will examine your EVERY/WIDTH phrase and calculate how many repetitions of the group it can fit within the LINE LIMIT. If you use the identifier form of the LINE LIMIT clause, report writer will do this dynamically when you GENERATE the groups.
If you omit the EVERY/WIDTH phrase, report writer will examine your TIMES phrase and will calculate how widely it can space the repeats of your group at regular intervals. You cannot use the identifier form of the LINE LIMIT clause in this case.
The rightmost column of the rightmost REPEATED group must not go beyond the LINE LIMIT. This possibility can arise only if you use both the TIMES phrase and the EVERY/WIDTH phrase. In all other cases, report writer does the fit for you and makes sure that the repeats will fit side-by-side without violating the LINE LIMIT.
The REPEATED clause is not allowed in a report group that has no LINE clauses.
Each instance of the group is produced by one GENERATE. For example, to produce the above 3-up pattern, you would issue three successive GENERATEs. Each instance may display different data and may differ from its companions in certain characteristics by virtue of any PRESENT or OCCURS... DEPENDING clauses that you have coded.
Report writer sets up a buffer to hold your repetitions. If your group is REPEATED three times, as in the diagram above, this is what happens:
First GENERATE: The group is not produced but is placed in the buffer; the special register REPEATED-COUNTER is set to 1.
Second GENERATE: The second group is also not produced but is placed in the buffer; REPEATED-COUNTER is set to 2.
Third GENERATE: All three groups are produced side-by-side, with the second and third groups offset by the number of columns given in the EVERY phrase. The buffer is then cleared, ready for the next three groups. REPEATED-COUNTER is reset to zero.
The starting point for the repetitions is given by the COLUMN numbers in your group description. These will become the COLUMN numbers of the left-hand group. The following example shows the effect obtained:
If a different body group is produced, no more groups are placed side-by-side and any groups already in the buffer are output. Any unused repetitions will result in blanks on the right-hand side. The effect of writing:
is shown in the following:
where A and B are DETAIL groups and A is REPEATED 3 TIMES.
Group B may also be REPEATED, but even if it is also REPEATED 3 TIMES, it will not be printed alongside group A, but will start a new series of repetitions. The same effect is seen if your program issues a TERMINATE when there are groups still in the buffer. report writer will first produce them with blank unused entries on the right, so that no data will be lost.
If you need to have different groups placed side-by-side, you will have to define a single group and use the PRESENT WHEN clause above several LINE entries to create the impression of different groups at run time.
If a control break occurs that results in a CONTROL HEADING or CONTROL FOOTING group, it has the same effect as when you GENERATE a different DETAIL group. That is to say, any groups in the buffer are first output. This is true even if your CONTROL group is a dummy (with no LINE clauses to cause output). Briefly, your groups always appear in chronological order.
If a clause in your group references LINE-COUNTER (in a condition or as a SOURCE), you will always obtain its correct effective value. report writer updates LINE-COUNTER just as though the group were actually being output, although the group is being placed in a buffer in memory. Then, when the next group is GENERATEd, LINE-COUNTER immediately reverts to the value it had at the start of the preceding group.
The page-fit test is applied to each repetition in turn. So, if your REPEATED group has a depth that may vary (because of a PRESENT WHEN clause or an OCCURS...DEPENDING at LINE level), room must exist for the largest group that has been GENERATEd in the current "pass" across the line.
You may place a REPEATED clause in a CONTROL HEADING or CONTROL FOOTING group, but this is of no use except when you use summary reporting (GENERATE report-name), because there
is no other way that the same CONTROL HEADING or CONTROL FOOTING group can appear twice in succession.
SIGN Clause: Coding Rules
If you write a SIGN clause in an elementary entry, the entry must have a numeric PICTURE with an "S" symbol.
This clause acts on elementary fields, but you may also code it in a group level entry, where it applies to all numeric elementary entries within the group whose PICTUREs begin with the "S" symbol.
Format b is unique to the REPORT SECTION. Each literal must be a single character non-numeric literal. At least one of the phrases must be present.
The format b SIGN clause enables you to place symbols of your choice on the left or the right of any signed printed item to represent a negative amount. The LEADING literal (if specified) is placed immediately before the first character of the report field. If leading spaces are suppressed with the Z or floating currency symbol, the literal is placed immediately before the first non-space character. The TRAILING literal (if specified) is placed in the last character position. For example, to place parentheses around a negative payment (a common accounting requirement), you would code:
which would output a value of -12 as: (12)
while a value of -1234 appears as: (1234)
This feature can be made to work for positive values by specifying the negative of the source (SOURCE (- PAY) in the case above).
SOURCE Clause: Coding Rules
Any valid COBOL identifiers or arithmetic expressions may be used as operands, including any COBOL term that may be the source item of a MOVE or COMPUTE; for example, report writer special registers such as PAGE-COUNTER, GLOBAL or EXTERNAL items, and special compiler registers such as LENGTH OF.
Each operand may be subscripted and/or qualified if necessary. For example:
The operand may have as many qualifiers, subscripts or indexes as are normally permitted for the subject of a MOVE statement. Relative subscripting and reference modification may be used.
You must also code a PICTURE clause in the same entry (unlike VALUE, which need not have a PICTURE). The PICTURE used must be compatible with the PICTURE of the operand(s). If you are in any doubt, look at the description of the identifier where it is originally defined in the FILE, WORKING-STORAGE or LINKAGE SECTION of your program. Ensure that its PICTURE is unedited and that you are not attempting to produce a COMPUTATIONAL field from a PICTURE X format. The two PICTUREs may be of unequal length, in which case there will be truncation or space-filling on the right (for a non-numeric field) or truncation or zero-filling on the left (for a numeric field). The rules for the SOURCE statement are exactly those of the MOVE or COMPUTE statements of procedural COBOL.
The SOURCE IS and SOURCES ARE keywords may be omitted, except when immediately following a VARYING clause. We shall still refer to the clause as a SOURCE clause, however.
An expression may be any arithmetic expression containing any of the following symbols and keywords:
+ for addition
In addition, the expression may have any number of identifiers, and these may be subscripted or qualified. Here are some examples of expressions:
The rules for forming an expression are exactly as for the COBOL PROCEDURE DIVISION, as described in your COBOL language reference. For more information see SUM Clause. The effect of a potential zero divide or size error depends on the choice of action on overflow. (See OVERFLOW Clause.)
The ROUNDED phrase may be used in the same entry if you use a numeric PICTURE that has fewer digits to the right of the decimal point than the SOURCE identifier. It will ensure that the value produced is the numerically closer of the two possible values, instead of always truncating the unwanted digits. You can use ROUNDED with a single identifier as well as with an expression. (So you need not code "+ 0" for ROUNDED to be legal.) In the following example:
if SALARY contains 100.50 or 100.60 or 100.99, the value produced will be 101, not 100.
For more details of the ROUNDED keyword, see in your COBOL language reference under the COMPUTE verb. ROUNDED is a clause in its own right and thus may be written at any location in the entry. If you have a multiple form of the SOURCE clause, or more than one such clause (see SOURCE Clause), ROUNDED will affect all of them wherever applicable.
You can indicate a multiple-choice entry by appending WHEN or UNLESS condition to the SOURCE clause, and then coding further consecutive pairs of SOURCE and WHEN/UNLESS clauses in the same entry (see Multiple-Choice Form).
The effect of the SOURCE clause is best described by reference to the COBOL MOVE or COMPUTE statements, because it obeys identical
The special registers CURRENT-DATE and TIME-OF-DAY of OS/VS COBOL and DOS/VS COBOL make use of the conceptual data items DATE and TIME.
If the report field has "<" PICTURE symbols, or begins in a variable position, report writer will not store the result directly in the report field, but will use an intermediate area.
Reference to controls
If the SOURCE clause refers, directly or indirectly, to a CONTROL operand, and the SOURCE is fetched at CONTROL FOOTING time, the contents of the control identifier before the control break will be used. This means you will obtain before-the-break contents for your control fields in the following report groups:
In every CONTROL FOOTING;
In the PAGE FOOTING and PAGE HEADING, if the page advance was caused by a CONTROL FOOTING group.
This rule applies whether the CONTROL operand is used as a SOURCE by itself, or as a subscript, or as part of an expression. It also applies if you refer to the CONTROL operand via a redefinition, or via a group field that contains it, or a subordinate field. This is because the pre-break values are temporarily stored directly back in the control fields outside the REPORT SECTION while CONTROL FOOTING processing is being done.
One important consequence of this rule is that, if you use fields defined under an FD in the FILE SECTION as controls, your program must not execute any report writer statements - not even a TERMINATE - after the input file releases the buffers. The correct order for "close down" is therefore:
See CONTROL Clause, and GENERATE Statement for further details.
You may include the keyword NONE to indicate that a particular field is to have no contents stored in it. It is then treated as ABSENT. An example of the use of NONE will be found under the LINE clause (see Multiple LINES Clause).
Your entry must be subject to at least one of the following:
A fixed OCCURS clause (not OCCURS...DEPENDING), or
A multiple LINES clause, or
A multiple COLUMNS clause.
The number of terms in your multiple SOURCES must equal the total number of repetitions the entry is subject to in all dimensions, or the number of repetitions of one or more of the inner dimension(s). For example, with the following layout:
The number of SOURCES should be either 2 (just the inner dimension), 6 (the product of the inner two dimensions), or 24 (all the repetitions).
If the terms cover more than one dimension, they are distributed along the innermost dimension, periodically stepping to the next entry in the outer dimension(s). For example:
will result in:
This technique is useful when your SOURCE items are not already conveniently arranged in a table or when, as in the case above, the order is irregular.
If there are two or more dimensions and the number of terms matches only the inner dimension(s), the terms are recycled from the first SOURCE operand for each repetition of some outer dimension. For example, in the following case:
the values of JAN, FEB and MAR will be repeatedly stored in each line. However, you may vary the contents actually stored by allowing a VARYING operand to advance in step with each occurrence of the outer dimension and by using it as a subscript in the lower-level entry:
If a ROUNDED phrase is present in the entry, every SOURCE item will be rounded.
The multiple SOURCES may be used as one or more of the alternatives within a multiple-choice entry. You need not use a multiple SOURCES in every alternative:
You may omit the SOURCE keyword, except when immediately following a VARYING clause.
Other examples of the multiple SOURCES clause will be found under Multiple COLUMNS Clause and Multiple LINES Clause.
STYLE Clause: Coding Rules
STYLE may be coded at any level, including in the FD (see Report Files) or RD (see REPORT SECTION and RD). The WHEN condition phrase cannot be used in the FD or RD entry. STYLE cannot be used if the device-name of the corresponding file is NONE.
NORMAL may be coded instead of a style-name, meaning that no special effect is to be produced. It must be the only style-name in the clause and there must not be a WHEN condition phrase.
Apart from NORMAL, each style-name names a style or special effect that must be obtainable from the output device. The type of output device in use is given in the TYPE clause of the SELECT statement. The style-names available are either predefined or user-defined for the particular output device. This check, and the processing of the styles themselves, may be delayed until run time by writing DEFERRED in the TYPE clause. This enables the program to run, in theory, with a variety of different output devices, even when they are widely dissimilar. For a mainframe, special device handling is usually the province of a user-written report file handler - see Installation and Operation. For example, STYLE HIGHLIGHT might be implemented by any of the following means:
The following are standard device-independent style-names. The first two are available with every TYPE of printer (other than TYPE NONE). The last two are available with all printers except the most basic.
UNDERLINE causes the report field to be underscored. It is used for headings.
HIGHLIGHT causes the report field to stand apart from the others, normally by appearing in bold or intense. It is used to give emphasis to certain fields.
ALT-FONT causes the report field to appear in a second contrasting font or typeface, such as italic.
GRAPHIC causes the report field to appear in a third contrasting font.
The remaining style-names used in the examples that follow are purely for the purpose of illustration, and are not necessarily available on any particular device.
Style-names are grouped into mutually-exclusive classes. Styles HIGHLIGHT, ALT-FONT and GRAPHIC are mutually-exclusive but UNDERLINE belongs to a separate (one-member) class. The classes are defined in the Printer Description File. It is not valid to code two styles belonging to the same class in the same entry. Thus the following clause is not valid:
However it is valid to place different members of the same class in nested entries, in which case the prevalent style is noted and restored at the end of the nested entry. Thus, in the following entries, TOMATO is RED while all the other entries are GREEN:
The STYLE clause cannot be repeated in an entry. Hence, if a multiple-choice entry is required, with a different STYLE on each choice, separate entries must be coded.
If STYLE is used in a report that uses the PAGE BUFFER feature it should not be coded in a Report Group Description at a level higher than the LINE level.
No style-name may be the same as one which is already in effect. For example, the following is illegal:
The STYLE clause cannot be used on an unprintable elementary entry.
By inserting non-printable control characters, or escape sequences, into the report data, before or after the data affected, or both.
By re-printing a line or part of a line without advancing the carriage. This method is commonly used to highlight text and occasionally to produce an underline effect.
By some special technique chosen and implemented by the user (see Independent Report File Handlers).
The method of implementation of each style is defined explicitly for each TYPE of device, and may be altered by the user.
The STYLE clause is transparent to the layout of the report. That is, it does not affect any of the other clauses or entries in the report description. For example, COLUMN numbers are unchanged, even though report writer may be inserting extra control sequences into the report lines. You can therefore simply add STYLE clauses to enhance existing programs.
Several STYLE names can be combined in one clause, for example:
Here the different characteristics are simply superimposed on each other (but see next item).
Two or more styles may be treated as related and perform a single action as a result of the combination. For example
One of these combinations might well be necessary to make use of a particular font and will result in a single escape sequence being sent to the device.
The combination of style-names can be coded in any order. It may also be represented by coding different parts of the combination at different levels . In the following example, the STYLE 10CPI clause at the group level may not necessarily cause any control characters to be output. Instead, it modifies the STYLE clauses below it, so that the effect is as though STYLE COURIER 10CPI and STYLE UNIVERS 10CPI had been coded at the lower levels:
The scope of the STYLE clause is decided by the level of the entry in which it is coded, thus:
a. In an elementary entry, the STYLE clause applies only to the elementary field, for example:
b. In a LINE entry, the STYLE clause applies to the whole line, as in:
c. In a report group entry, the STYLE clause applies to the whole group, for example:
d. In an RD entry, the STYLE clause applies to the entire report:
If any control characters are output, this happens during the execution of each INITIATE or TERMINATE for the report, or both.
e. In an FD entry, the STYLE clause applies to the entire report file:
If any control characters are output, this happens during the execution of each OPEN or CLOSE for the file, or both.
The WHEN clause causes the STYLE to take effect only when the condition is true, for example:
Since you can only code STYLE once per entry, you cannot vary the STYLEs in a multiple-choice entry, and instead must code separate entries, as here:
If STYLE is defined on an elementary field that has suppressed zeros or trailing spaces, the STYLE will apply only to the characters printed. For example, the coding:
might result in:
15 PAYMENT OVERDUE
3156 PAYMENT OVERDUE
152722 PAYMENT OVERDUE
This clause automatically forms totals from any other numeric field. You may also use it as a term in an arithmetic-expression in a SOURCE clause.
SUM Clause: Coding Rules
There are two ways to code the SUM clause:
As a clause in its own right. You write the clause in place of a SOURCE, VALUE, or FUNCTION clause. For example:
As a term in an expression; for example
This type of expression can only be used as a SOURCE operand (although, as usual, the SOURCE keyword is optional). You cannot use a SUM term as part of a condition or, for instance, as a parameter to a FUNCTION.
The item summed can be either of two things:
The name of any numeric data item in your REPORT SECTION (other than a FUNCTION entry). To use this, you must place a data-name on the item in the REPORT SECTION you want to total. Suppose you need to form a total from the following report field:
Just place a data-name of your own choosing on it, such as:
and you may now write SUM OF R-WAGES in another item in your report to form a total. This is called a REPORT SECTION SUM clause. A REPORT SECTION SUM operand never has any subscripts or arithmetic symbols - you can write only: SUM OF data-name.
The data item referred to in the SUM clause may be qualified by the report-name, as in SUM R-PAYMENT IN SUMMARY-REPORT. By default, the qualifier is the same report as the one in which the SUM is defined. So if the same data-name appears in more than one report, it may be referred to by a SUM clause in its own report without qualification. (It cannot be referred to by a SUM in a different report without a qualifier.) This means that you can duplicate a complete report description with SUM clauses without changing any of the data-names on SUM entries.
A numeric identifier or expression from outside the REPORT SECTION. In this form, it is similar in appearance to the operand of a SOURCE clause. This is called a non-REPORT SECTION SUM clause.
(Unless a naming convention is observed, there is no way of telling from the data-name whether the SUM clause references a REPORT SECTION SUM or not. In the examples in this volume, we sometimes use a prefix such as "R-" to designate a REPORT SECTION item, so that "SUM OF R-..." will be recognized as a REPORT SECTION SUM. Observing a standard like that will make your REPORT SECTION easier to follow.)
A SUM clause may total several items, and you may combine REPORT SECTION and non-REPORT SECTION items; for example:
where W-BASIC is a non-REPORT SECTION item, R-BONUS is a REPORT SECTION item in a different report group and R-OVERTIME is a REPORT SECTION item in the same report group. In this case, the total field is always the sum of the individual totals that would be formed from each of its items. You should then interpret the remarks in the remainder of this section for each of the single SUM operands individually. Note that this is not similar to the multiple SOURCES clause (despite their syntactic similarity), since only one printable item is defined with the SUM clause.
Your report may contain as many entries with SUM clauses as you wish, in any TYPE of group (even RH). Only elementary entries can have a SUM clause.
If you code the UPON phrase, each group-name must be the name of a DETAIL group and should not be the same group as the group you are currently defining. The group-name may be qualified. If not, the current report is assumed.
If your SUM clause is in a DETAIL group and the operand of your SUM clause is not in the REPORT SECTION (a rare situation), your report should contain more than one DETAIL group and you should logically code the UPON phrase, in order to specify on which GENERATE you want adding to take place.
If you code the RESET phrase, the control-id operand must be one of those defined in the CONTROL clause of your report (including REPORT, whose presence is assumed there). If you are currently defining a CONTROL FOOTING group, the level of the control in your RESET ON should be higher than the level of this group. (It may also be equal to the level of the current group, in which case resetting occurs at the normal time, and the phrase is therefore redundant.)
The RESET phrase cannot be defined anywhere in a multiple CONTROL FOOTING group.
You may code the SUM clause more than once in an entry. The effect of this is to add together the totals formed from each of the clauses. Hence:
(and, if A and B are non-REPORT SECTION items, SUM (A + B)). This separation is essential only if you need to use a certain UPON phrase with one but not the other, for example:
ANS-85 note. Since a reference-modified identifier is regarded as non-numeric, you cannot SUM it, either directly as the operand of your SUM clause, or indirectly by naming a REPORT SECTION item where it is used as a SOURCE.
SUM Clause: Operation
The method used for totalling depends on whether the item referred to by SUM is a data-name on a REPORT SECTION entry (called henceforth a "REPORT SECTION SUM "), or not.
Whenever the originating data item named in your SUM clause is output in the report, the item it references is also added into the (internal) total field. If the REPORT SECTION data item totalled contains a SOURCE or VALUE clause, the amount added to the total is the SOURCE or VALUE operand outside the REPORT SECTION, not the intermediate REPORT SECTION field. For example, if you write:
the fields added into the total will be 100 and W-PAYMENT, not the report fields R-FLD1 and R-FLD2. Thus, if W-PAYMENT has a PICTURE of 9(5)V99 rather than 9(4), the full originating value - not the truncated value that appears in the report line - will be added.
There are two names used to distinguish two cases of REPORT SECTION SUMming:
In the next illustration, the item to be totalled is in the same report group as your SUM clause:
The SUM entry may appear earlier in the report group than the item it is totalling and this may be carried on to any number of stages. Thus the physical
order of totals and items being totalled within a single group is immaterial. Report writer decides for itself the order in which totalling must be done.
Hence the correct result is obtained by coding for example:
In this example, the "boxes" contain instances of the different report groups. The values to be added appear in a DETAIL, and the total is in a CONTROL FOOTING.
You may use also this method of summing between any reasonable combination of groups, namely any of the following:
¶ Lower CONTROL FOOTING to higher CONTROL FOOTING,
¶ DETAIL to DETAIL,
¶ Any group to a REPORT FOOTING,
¶ Any body group to a PAGE FOOTING,
¶ PAGE FOOTING to a CONTROL FOOTING.
Frequently there are several items that could be rolled forward to produce the same result. For example, your YEAR totals are the total of the twelve MONTH totals; they
are also the total of your fifty-two WEEK totals and your 365 DAY totals. Rolling forward the immediately-lower-level total (such as MONTH totals into YEAR totals) is the most efficient
If SOURCE SUM correlation is in effect (see Subtotalling and SOURCE SUM correlation), adding takes place when any DETAIL is being GENERATEd that contains the same identifier as a SOURCE item as the identifier appearing in the SUM clause.
If the UPON phrase is used, adding takes place when a DETAIL group specified in that phrase is GENERATEd.
If SOURCE SUM correlation is not in effect and there is no UPON phrase, adding takes place on each GENERATE that refers to the report.
Almost all totalling can also be accomplished by means of REPORT SECTION SUM clauses.
the internal total field (which is fully described below under Use of Total Fields) is MOVEd to this report field, and edited according to the given PICTURE, according to the same rules as the SOURCE clause.
Resetting the total
The total is reset (cleared to zero) at the end of the processing for the report group in which it is defined, unless you override this using the RESET phrase as described below (see RESET Phrase). Thus the total field remains available for use anywhere in the same group (within a SOURCE for instance) before its contents are erased.
When adding a value into the total, the report writer code obeys the rules of the ADD statement. Unless you coded SUM OVERFLOW PROCEDURE IS OMITTED in the RD, a SIZE ERROR test is always done and if there is size error, a run time error is signalled at once.
If the SUM clause appears in a multiple CONTROL FOOTING group, the SUM clause has its usual effect in the lowest level group and in the higher levels acts by rolling forward each previous level. For example, in the following structure:
the SUM clause acts like three different SUM clauses. At the lowest level (CITY), it behaves as defined (by subtotalling W-PAY). The CITY total is then rolled forward into the COUNTY total on change of CITY and the COUNTY total is rolled forward into the STATE total on change of COUNTY.
Summing a Repeated Item
If you wish to sum a repeating item, you may form totals along any of four different axes. These are, from minor to major:
Axis 1: COLUMN Axis
Axis 2: COLUMN-Group Axis (below LINE and above COLUMN)
Axis 3: LINE Axis
Axis 4: LINE-Group Axis (above LINE and below report group)
Report writer will automatically total the repetitions of your field along any axes necessary to form the total. The direction of the adding depends not on the
syntax of the clause you use but on where you place it. If your SUM clause has no repetitions at all (is not subject to
an OCCURS clause or a multiple LINE or COLUMN clause), report writer will total all occurrences of the field. You can thus total a REPORT SECTION table of any number
of dimensions. If your SUM clause is part of a repeating report field, then the item being summed must repeat the same number of times along the same
axes as the SUM entry. Your field will be output along any of the axes shared and totalled along any of the axes not shared
by the SUM entry. An example will make this clearer. In the following case, the field R-QUARTER has an OCCURS clause in two
axes: the LINE axis and the COLUMN axis.
The following code produces this layout:
To obtain row totals, code the SUM clause as an entry at a level within the same LINE as the items referred to in SUM. (The entry below is named ROW-TOTAL but you may choose any data-name). To obtain column totals, place the SUM clause within a separate LINE and give it the same number of horizontal repetitions as its operand. (The entry below is arbitrarily named COL-TOTAL.) The final result is as follows:
Notice that the field ALL-TOTAL could also have been coded as SUM OF R-QUARTER (which is less efficient) or SUM OF ROW-TOTAL. Also notice that the data-names ROW-TOTAL and ALL-TOTAL are not referenced and could have been omitted.
You may require just a single total of all the entries (the "corner" total in the above illustration), without any row or column totals. Just write the ALL-TOTAL entry alone:
The examples shown earlier cover only two out of the four possible axes. You may also SUM along the other two axes, that is: groups of COLUMNs and groups of LINEs. As an example of groups of COLUMNs, take this layout, where we total the four weeks in each month horizontally:
This example also illustrates the fact that cross-foot totals need not appear to the right, or below, the figures from which they are formed.
If your program contains more than one report, you are not restricted only to rolling forward within one report. A SUM clause in one report may refer to a named numeric data item in a different report. As with totalling in a single report, the value of the referenced field is added whenever the field is output. (This does not apply to non-REPORT SECTION summing, however, when SOURCE SUM correlation is in effect: see ALLOW Clause.) Note that all total fields in a Report are cleared by the INITIATE statement for the report. Therefore, if you need to SUM from one report to another, be sure that both are INITIATEd at the start of the processing.
A PRESENT WHEN clause may test the value of any total fields referenced in its condition-operand. However, it should then not contain within its scope either an entry
with a SUM clause or an entry that is summed by a SUM clause. See Effect of PRESENT WHEN on SUM.
It is not possible to accumulate in an instant a single total all the entries in a table outside your REPORT SECTION without using an intermediate unprintable table as in the example above. However, you may use a non-REPORT SECTION SUM clause to accumulate - over time - single entries in a table into a corresponding matching number of totals, typically in a CONTROL FOOTING. Since your SUM operand is not in the REPORT SECTION, you may use subscripts with it, just as you would in the SOURCE clause:
If the SUM operand is not in the REPORT SECTION, you may also total arithmetic expressions, such as:
An evaluation is performed for the expression on every GENERATE, before the result is added into the total field, so the use of this technique is less efficient - and more susceptible to rounding errors - than a method using unprintable intermediate totals. (The accumulation is not affected by the status of SOURCE SUM correlation.)
The internal total field is a pure numeric, signed COMPUTATIONAL field with as many integral and fractional digits as the SUM entry. Hence, no precision will be lost when the total field is stored in the report field. If the SUM clause refers to a REPORT SECTION item, the precision of the total field is increased if necessary so that it has at least as many integral and fractional digits as the entry being totalled. Hence the total will have at least the precision of the field being totalled, rounding or truncation taking place, if indicated, when the field is output, not while it is being accumulated. Here are some examples:
PICTURE in SUM Entry PICTURE of SUM Operand PICTURE of Internal Total
if in REPORT SECTION
99999 (not in REPORT SECTION)
In a SOURCE Clause
You may capture an internal total field with a SOURCE clause reference, either as its single operand or as a term in an operand that is an expression. The value you obtain depends on the category of the total field you access, as follows:
SOURCE Refers to Total Field Defined in the Same Report Group
You will always obtain a true value of the total as specified. The position of the SOURCE clause within the group is immaterial, as report writer always computes the totals before producing any of the group's report lines (which is when SOURCE operands are filled in).
This feature is useful when you wish to form an unprintable total from a non-REPORT SECTION field without loss of precision and then output it ROUNDED
. You might wish to form totals to cents precision and output them to the nearest dollar. You should then write two entries
in the same report group, one of which has no COLUMN clause and is therefore unprintable, as in this example:
If you had written instead:
the internal total field would have the implied PICTURE S9(6) COMP, so you would lose precision each time the (truncated) value of WS-FIELD is added in. Truncation would not arise if the SUM operand were a REPORT SECTION data-name, since the precision of the summed field is then also taken into account in establishing the required precision of the sum field.
Alternatively, you may make use of report writer's less efficient but highly accurate default PICTURE S9(12)V9(6) for SUM terms in SOURCE clauses, by coding:
The next example uses an arithmetic expression involving total fields:
It would also have been correct to code the last entry as:
However, the first code shown is more economical since we are printing the individual totals R-TOT-INCOME and R-TOT-TAX already elsewhere and can therefore re-use them in the expression instead of summing them again.
SOURCE Refers to Total Field Not Defined in Same Group (Snapshots)
If the SUM total field referred to in turn refers to a non-REPORT SECTION item (subtotalling) or to an entry in a different report group (rolling
forward), you will obtain at that instant the up-to-date accumulated value, a technique which is useful for obtaining brought forward and carried forward totals, as in the layout
on the following page:
We reference a SUM total field in a SOURCE to capture a snapshot of the running total. The SUM entry is gradually accumulated over a certain part of the report, so we obtain any number of versions of it at any state up to the eventual total. This, incidentally, gives us an alternative to the RESET phrase for forming cumulative (running) totals.
In the sample code we save the SUM total field procedurally in a working location (WS-TOT-CASH) after each GENERATE and use that in the SOURCE for the next cycle. This is done for two reasons:
It is independent of whether or not the option is in effect. The (standard but "less logical") option does rolling forward and subtotalling before the page-fit test (see GENERATE Processing Cycle), so our total fields will already have been updated by the new value of CASH and we would otherwise have to subtract it again in the SOURCE to get the true total. The option corrects this anomaly, but there is a second problem:
Whichever option is in effect, the total field is reset to zero immediately after its CONTROL FOOTING group has been output, so it cannot appear in the PAGE FOOTING beneath it (the last page in our example, since the group is a CF FINAL). Hence the use of WS-TOT-CASH which is the current total "suspended from the last GENERATE".
If we did not wish to print a grand total field from which to "snapshot" the values, we could define the total as an unprintable item (with no COLUMN clause).
TOTAL-CASH is an unprintable SUM entry that is - as necessary - outside the scope of the PRESENT WHEN. (If your entire LINE is subject to the PRESENT WHEN, place your unprintable field in another LINE of the same group. Since it is unprintable, its placement is immaterial.)
You may use the total field even if it is defined later in the same group because totalling is completed for each group before production of any
of the report lines begins.
You may also procedurally alter (that is, ADD TO, SUBTRACT FROM etc.) the value of any named total field at any time. Of course, if you do so the results that appear in the total fields will be different from those you would expect if report writer alone were accumulating the totals. You may also need to handle any possible size errors in the total field. The values you added or subtracted will be reset with the rest of the value at the usual time.
Total fields are cleared to zero by the INITIATE statement. They will also normally be zero after execution of the TERMINATE statement. This is because they are always cleared after being output, and the TERMINATE statement outputs all CONTROL FOOTING groups and any PAGE FOOTING and REPORT FOOTING. However, if a SUM clause was coded in another type of group, such as a DETAIL, that is not automatically output when your program issues the TERMINATE, there could be a non-zero total waiting in vain to be output. Also, if the SUM clause was conditional, the field with the SUM might have been absent on the last occasion, in which case a non-zero total might still be waiting to be output. In all these cases, report writer will issue a run time error and the total will be cleared if and when your program issues another INITIATE for the corresponding report.
Any cross-foot totals for the group will already have been calculated in all cases.
If OSVS is in effect, any rolling forward (from this group into a different group) and subtotalling (if this is a DETAIL group, or a PH or PF triggered by a DETAIL group) are done before entry to the Declarative SECTION. Hence you will obtain all totals fully updated. (See GENERATE Processing Cycle.)
If OSVS is not in effect, by contrast, any rolling forward and subtotalling are done after entry to the Declarative SECTION. So, especially if your group is a PAGE FOOTING (or HEADING), you will obtain an accurate value of the total at that "physical point" in the report.
Precision of SUM terms
If you use SUM or COUNT as a term in a SOURCE's expression, report writer will assign the internal total field with PICTURE S9(12)V9(6) COMP , irrespective of the PICTURE of the report field.
Report writer adds the SUM operands ("addends") directly into the total field, following the normal rules of the ADD statement. If there is a size error, the same action takes place as for REPORT SECTION SUM totals, as described above.
SOURCE SUM Correlation.
The decision as to when to add the items depends on whether SOURCE SUM correlation is in effect. This is the chief difference between the ANS-68 standard used in OS/VS and DOS/VS COBOL, which automatically applies SOURCE SUM correlation, and the ANS-74 and ANS-85 standards, which do not. You will observe a difference only when the following circumstances occur simulataneously:
When your report has more than one DETAIL group; and
When your program SUMs an operand that is also a non-REPORT SECTION SOURCE operand in one or more of the DETAIL groups.
Otherwise, report writer will not apply SOURCE SUM correlation. SOURCE SUM correlation is in effect if:
The precompiler was installed with the OSVS option set on, or
You code an ALLOW SOURCE SUM CORR clause in your RD.
SOURCE SUM correlation is not in effect if:
Your system was installed with the OSVS option set off (ANS74 or ANS85), or,
You code an ALLOW NO SOURCE SUM CORR clause in your RD.
If SOURCE SUM correlation is in effect, report writer takes each non-REPORT SECTION operand specified in your SUM clause and scans the DETAIL groups of your report to establish whether the same item is coded in more than one of them as a SOURCE operand. (The SOURCE keyword may, as usual, have been omitted.) Arithmetic expressions are not examined. Redefinitions of the same item and differences in subscripts or qualifiers (apart from interchanging the words IN and OF) mean that there is no match. All your DETAIL groups are scanned in this way. The appearance of the same operand more than once as a SOURCE in the same DETAIL counts as only a single match. If a match is found, report writer will add the item into the total field only when the DETAIL or DETAILs that contain your item are GENERATEd. If no match is found, report writer will add the item into the total field on every GENERATE for that report.
Using a dummy DETAIL group for Summary Reporting.
With the ANS-68 standard of OS/VS and DOS/VS COBOL, a corresponding SOURCE was required for every SUM. This meant that in a totals only report, a dummy DETAIL group needed to be defined, as in the following sample:
Although report writer accepts this code unaltered, the dummy group is now unnecessary - even if SOURCE SUM correlation is in effect. The dummy group in the example above may be deleted and the GENERATE replaced by GENERATE report-name:
More details will be found under "Summary Reporting" (see GENERATE Statement).
If SOURCE SUM correlation is not in effect, report writer will add every operand of the SUM clause into the total field on every GENERATE for the report.
The recommended method of report writer is to place a data-name on the entry to be totalled (omitting the COLUMN clause if it is not be printed), and SUM the item using that data-name.
If SOURCE SUM correlation is in effect and both the SOURCE operand and the SUM operand names are identical, the item will be added, as expected, only when the SALARY group is GENERATEd.
Using the UPON phrase. You may use this whether or not SOURCE SUM correlation is in effect, because UPON overrides its effect. By writing UPON SALARY-GRP (where SALARY-GRP is the 01-level name of your DETAIL group), you ensure that the item will be added into the total only when the SALARY-GRP DETAIL group is GENERATEd.
The next example compares these methods:
a. Method Using REPORT SECTION SUM (recommended)
b. Using SOURCE SUM Correlation:
c. Using the UPON Phrase:
In all our examples presented earlier in this section, the total field is reset to zero at the end of the processing for the group in which it has appeared. Sometimes you will not want this to happen. Such a case is called a cumulative (or running) total. Here the total is not necessarily cleared or reset after it has been output. Values then continue to be added into the total. You will have seen above that you can capture cumulative totals by "taking a snapshot" of a higher-level total field. Another method is to use the RESET phrase. Its operand states at which (normally higher) level of control break, if any, the total field is to be cleared. If you specify RESET ON REPORT (or RESET ON FINAL), the total field will not be reset after the final control footing has been presented, during the execution of the TERMINATE.
For example, by writing:
you ensure that the total field is not cleared until a new BRANCH-CODE is reached.
Here is an example of a cumulative total:
This clause is used at the 01-level to indicate which of the seven possible types of report group is being defined.
where control-id is an identifier in the CONTROL(S) clause, or the word REPORT or FINAL.
TYPE Clause: Coding Rules
Write the TYPE clause at the 01-level entry only. You may omit the keywords TYPE IS. If you do not code a TYPE clause for a group, it will be assumed to be TYPE DETAIL.
All TYPEs of report group are optional, whatever the circumstances, but every report must have at least one body group (CONTROL HEADING, DETAIL, or CONTROL FOOTING).
PAGE HEADING, PAGE FOOTING and the OR PAGE phrase of CONTROL HEADING groups are allowed only if you have a PAGE LIMIT clause in the RD.
In the CONTROL HEADING and CONTROL FOOTING forms each control-id operand must be chosen from the list of controls in your CONTROL clause, including REPORT (or FINAL) which is always assumed present.
If CONTROL HEADING is coded with no control-id operand, there must not be more than one control-id in the CONTROL(S) clause. The clause is then taken to mean CONTROL HEADING FOR control-id, if there is just one control-id in the CONTROL(S) clause, or CONTROL HEADING FOR REPORT if there is no CONTROL(S) clause at all.
If more than one (different) control-id is coded in the CONTROL FOOTING form, the result is a set of multiple CONTROL FOOTING report groups. The control-ids need not be coded in any particular order and need not form a consecutive hierarchic sequence. For example, if the CONTROLS clause is:
it is permissible to code:
which means the same as
If a CONTROL FOOTING is required for all levels of control, ALL may be coded instead of the exhaustive list of control-ids.
If a DETAIL group also has the same format as some CONTROL FOOTINGs, it is usually worth the effort to define it as the lowest-level CONTROL FOOTING group, and force a lowest-level control break on each GENERATE, in order to make full use of this feature. In this case summary reporting is used (see GENERATE Statement) and each totalled value, generated by a SUM clause, will be the "total" of just a single value in the case of the lowest CONTROL FOOTING.
If CONTROL FOOTING is coded with no control-id operand, it is taken to mean CONTROL FOOTING FOR ALL or, CONTROL FOOTING FOR control-id , if there is just one control-id in the CONTROL(S) clause, or CONTROL FOOTING FOR REPORT if there is no CONTROL(S) clause at all.
In any report you may have any number of DETAIL report groups, but only one PAGE HEADING, PAGE FOOTING, REPORT HEADING, REPORT FOOTING, and each control-id may appear in only one CONTROL HEADING and only one CONTROL FOOTING group. If CONTROL FOOTING FOR ALL is coded, it must be the only CONTROL FOOTING in the report.
The physical order of report group descriptions is irrelevant. For example, the PAGE HEADING group need not necessarily appear before the DETAIL and PAGE FOOTING. Report writer produces them in the correct sequence according to the rules for page-fit and control break testing. However, for ease of maintenance, the order implied in the format above is recommended. Also, it is helpful if CONTROL HEADING groups are coded in major-to-minor order and CONTROL FOOTING groups in minor-to-major order, paralleling the sequence in which these groups will be presented in the report.
In a report with a PAGE LIMIT clause, if your group contains any absolute LINE clauses, report writer will check that each line of the group will lie within the region of the page appropriate to the TYPE of the group. Refer to the diagram of the regions of the page (see PAGE LIMIT Clause: Operation). REPORT HEADING and REPORT FOOTING groups may appear anywhere on the page from the HEADING position onwards. If your group contains only relative LINE clauses, and the report has a PAGE LIMIT clause, report writer will check at compilation time that your group is not larger than the appropriate region of the page, allowing for any other groups that may share that region (that is, a REPORT HEADING appearing above the first PAGE HEADING, or a REPORT FOOTING appearing below the last PAGE FOOTING).
All the CONTROL HEADING groups with an OR PAGE phrase must be able to fit on the page above any other DETAIL or CONTROL HEADING group. Stated precisely: (a) each DETAIL or other CONTROL HEADING must either have only relative LINE clauses or must begin with an absolute LINE which is higher than the highest possible line number produced by the CONTROL HEADING groups with an OR PAGE phrase, and (b) the LAST DETAIL value must be sufficient to accommodate the largest such combination.
If your report contains both a REPORT HEADING and a PAGE HEADING group, report writer will attempt to place them both in the Page Heading region of the page. If it can do this without overlap, without overflowing the region, and without violating any of the above rules, then your REPORT HEADING group will be produced on the first page of the report, above the PAGE HEADING. If the PAGE HEADING has relative LINE clauses, it begins relative to the last line of the REPORT HEADING. If, despite this, you require the REPORT HEADING to appear on a page by itself, you should code NEXT GROUP NEXT PAGE in the 01-level entry of the REPORT HEADING, to suppress this check.
If you want the REPORT HEADING to appear on the first page above the PAGE HEADING and "push it down" so that your DETAIL groups start lower on the first page than they do on the remaining pages, you should omit the FIRST DETAIL sub-clause. Your DETAIL groups will then begin on the line following the PAGE HEADING . To get extra space before your first DETAIL group, you may define a blank LINE entry at the end of your PAGE HEADING:
You may also achieve the same result without using a REPORT HEADING, by including all the lines in a single PAGE HEADING and using a PRESENT AFTER REPORT clause (see PRESENT AFTER Clause).
PF and RF together
If your report contains both a PAGE FOOTING and a REPORT FOOTING group, report writer will attempt to place them both in the Page Footing region of the page. If it can do this without overlap, without overflowing the region, and without violating any of the above rules, then your REPORT FOOTING group will be produced on the last page of the report, below the PAGE FOOTING. If the REPORT FOOTING has relative LINE clauses, it begins relative to the last line of the PAGE FOOTING. If, despite this, you require the REPORT FOOTING to appear on a page by itself, you should code an ON NEXT PAGE phrase in the first LINE clause of the REPORT FOOTING, to suppress this check.
If your report contains any such TYPE CH groups with the OR PAGE phrase, the CONTROL HEADING group will be presented after a control break at the relevant level, exactly as when the PAGE option is not present, but in addition, the actions on page advance processing are modified as follows:
If a DETAIL group causes a page advance then, after the usual page advance has taken place, the CONTROL HEADING group is printed. If more than one TYPE CH group has the OR PAGE option, these CONTROL HEADING groups are printed in hierarchic order, from highest to lowest. Each CONTROL HEADING is, of course, printed on the new page, irrespective of whether or not it would fit on the previous page.
If a CONTROL HEADING group causes a page advance, the same action occurs as in (a) above, except that the CONTROL HEADING group that caused the page advance is output only once on the new page, whether it has the OR PAGE phrase or not.
If a CONTROL FOOTING group causes a page advance, the same action occurs as for a DETAIL except that no CONTROL HEADINGS below the level of the CONTROL FOOTING are printed.
If a group has CH FOR PAGE without a control-id, it will be treated as equivalent to CH FOR PAGE OR REPORT.
The following shows the layout you might require:
Note the following labelled points in the diagram:
(A) Because of the OR PAGE phrases, both CH groups re-appear at the top of the page even though neither control has changed .
(B) When a control break occurs and the corresponding CH group will not fit on the current page, it appears once only at the top of the new page, even though it has an OR PAGE phrase.
(C) If a CF group causes a page advance, the CH groups are produced at the top of the next page, but only those at the same level or above that of the CF group.
The following is the report writer code required to produce this layout:
This clause is allowed for documentary purposes in the REPORT SECTION, for consistency with basic COBOL, or to emphasize that an entry is DBCS.
DISP is synonymous with DISPLAY.
Only non-DBCS items may be subject to USAGE DISPLAY and only DBCS items may be subject to USAGE DISPLAY-1.
No other forms of the USAGE clause are permitted in the REPORT SECTION.
indicates that the item (or items if on a group level) is DBCS (Double-Byte Character Set), such as Japanese Kanji. However, it is not
required in the REPORT SECTION, since it is implied by the presence of a DBCS PICTURE string (containing the symbols "G" and "B" only) or a DBCS literal, of the
form G"so...si" or G'so...si' where so and si are the shift-out and shift-in characters. DBCS items are stored
with a shift-out character on the left and a shift-in on the right. Each double-byte character occupies one print column position even though it takes up
two bytes of memory. COLUMN numbers (absolute or relative) take this into account. Spaces inserted between DBCS items are the regular (non-DBCS) space.
VALUE Clause: Coding Rules
You may specify a numeric or non-numeric literal, including a figurative constant, or a DBCS literal. An ANS-85 SYMBOLIC CHARACTER is also permitted.
Unless you specify ALL or a figurative constant, you do not need a PICTURE clause. For example:
You may use 'apostrophes' instead of "quotes" if your current compiler options expect them. The Precompiler accepts either delimiter at the start of a literal, scanning for the same delimiter to close the literal. Continued literals are also permitted. As usual, two quotes juxtaposed within a "literal" signify a single quote as part of the value, and similarly for apostrophe.
You may use the ALL "literal" form or a numeric literal or figurative constant, but in all these cases you must specify a PICTURE. Here is an easy method of coding a repeated value:
which gives you the repeated pattern: XOXXOXXOXXOXXOXXOXXOX
If the item is defined as DBCS by virtue of its PICTURE clause or USAGE DISPLAY-1 clause, the literal must also be DBCS. However a PICTURE clause is not required, a PICTURE of G(n) where n is the number of double bytes being assumed in default.
Any literal may also be hexadecimal. However, it is inadvisable to use this facility to insert printer control characters into your print data, since these will (a) make your program non-portable and unreadable (b) put your COLUMN positions out of alignment. The STYLE clause is designed specifically for this purpose and has none of these drawbacks. (See STYLE Clause.)
Report writer will either "pre-set" (fill in) your report field with the specified literal at compile time; or it may move the literal into the report field at run time, in cases where the report field is in a variable position, or where the report line cannot hold pre-set values because it is subject to an OCCURS clause.
If the item is DBCS, it is stored in the report line with each double-byte character occupying one column position. (See USAGE Clause.)
If you wish to place no value in a particular occurrence, you may simply code a space character: " ".
Your entry must be subject to at least one of the following:
A fixed OCCURS clause (not OCCURS...DEPENDING), or
A multiple LINES clause, or
A multiple COLUMNS clause.
All the literals must be either DBCS or non-DBCS.
The rule for the number of literals allowed in your multiple VALUE is similar to that of the multiple SOURCES clause (see Multiple SOURCES); that is, it must exactly equal either the total number of repetitions in all the dimensions of the entry, or the product of the numbers of repetitions of one or more of the inner dimension(s). For example, with the following layout:
the number of literals should be either 4 (just the inner dimension), 12 (the product of the inner two dimensions), or 24 (all the dimensions).
If the literals cover more than one dimension, they are distributed along the innermost dimension, periodically stepping to the next entry in one or more outer dimensions. For example:
will result in:
If there are two or more dimensions and the number of terms matches only the inner dimension(s), the series of literals is re-cycled from the first operand for each of the outer repetitions. For example, the following case:
will result in:
The multiple VALUE operand may be used as one or more of the alternatives in a multiple-choice entry. You need not use a multiple VALUE in every alternative:
If, as is usual, you omit a PICTURE clause, the size of each field is the size of its corresponding literal, as seen in the following example:
This is also true of multiple-choice entries.
In all cases, you may omit the VALUE keyword.
Other examples of the multiple VALUE clause will be found under Multiple COLUMNS Clause and Multiple LINES CLause).
VARYING Clause: Coding Rules
You may write any number of different data-name operands in this clause, each with an optional associated FROM and BY phrase.
Your entry must also have either an OCCURS clause or a multiple COLUMN clause or a multiple LINES clause.
Your data-names must not be defined already anywhere else in the program and you should not attempt to define them separately. Report writer creates a description for them itself, internally. (This is similar to the way COBOL handles index-names.)
You can re-use the same data-names in different VARYING clauses, provided that you do not do this when the clauses are nested (enclosed one within the other). For example, you could write VARYING R-LINE on each repeating LINE, and VARYING R-COL on each repeating COLUMN, throughout your program.
If you intend FROM 1, you may omit the FROM phrase and report writer will infer it. Likewise, if you intend BY 1, you may omit the BY phrase and report writer will infer it. (FROM 1 and BY 1 are the most usual requirements, so these assumptions are convenient.)
Each expression may be any integer, or an identifier, or an arithmetic expression, provided that the result has an integer value. The expression may contain data-names of an enclosing VARYING clause. It can also use a data-name of the same VARYING clause, but only in its BY expression. It must not contain data-names of an enclosed VARYING clause, or of any other VARYING clause. Thus the following are legal:
but the following are illegal:
VARYING Clause: Operation
When report writer is about to produce the first occurrence, it places the FROM value in an internal named data item set up implicitly by the VARYING clause. This is repeated, in the order given in the clause, for any additional data-names that may have been specified in the VARYING clause.
When report writer is about to produce each of the remaining occurrences, it adds the BY value to the data item. This is also repeated, in the order given in the clause, for any additional data-names that may have been specified in the VARYING clause.
The VARYING clause enables you to produce different source-items or values in successive appearances of a repeated field. Here are some examples:
a. To generate the numbers 1 through 10 in a line:
b. To output a two-dimensional array in Working-Storage into a two-dimensional array in your report (for example daily costs for four seven-day weeks):
c. You could display each week's entries from right to left by writing:
d. Now let's display the same entries, except that they are all held in a one-dimensional array of twenty-eight entries. (This example is important .)
As each week is processed, START-DAY-NO takes values 1, 8, 15 and 22. DAY-NO takes the seven values 1 to 7, then 8 to 14, then 15 to 21, then 22 to 28 in turn, each time starting with the new value of START-DAY-NO. In the clause VARYING START-DAY-NO FROM 1 BY 7, the phrase FROM 1 could have been omitted and in the clause VARYING DAY-NO FROM START-DAY-NO BY 1, the phrase BY 1 could have been omitted.
To produce a pyramid-shaped design:
Note that VARYING can also be used with a multiple COLUMN or LINE, as the following example shows:
To set up a "running index" which continues each time from its latest value, do not code something like VARYING R-WEEK FROM R-WEEK + 1 , but calculate the starting value explicitly.
To give your counter a series of values, say W-CNT (1), W-CNT (2), which are not formed by simple incrementing, write:
By experimenting with the VARYING clause, you will discover many novel and surprising uses.
WRAP Clause: Coding Rules
The AFTER phrase gives the rightmost column number that any field may occupy before wrap round becomes necessary. If integer-1 is specified, it must lie in the range 1 to maximum line width. Its value acts as a maximum line width for any lines in its scope. The rightmost column position of every entry with an absolute COLUMN must therefore not exceed integer-1. If identifier-1 is specified, a similar check is made at run time. If the phrase is omitted, a value of the LINE LIMIT is assumed for integer-1 and, if the identifier form of LINE LIMIT is in use, its value will be computed, as usual, at INITIATE time. Thus, by default, lines are allowed to reach the usual page width before wrap round.
The TO phrase gives the column number at which printing continues after wrap round. If integer-2 is specified, it must lie in the range 1 to maximum line width. If identifier-2 is specified, a similar check is made at run time. If the phrase is omitted, a value of 1 is assumed for integer-2. Thus, by default, a line wraps round to column 1.
The STEP phrase gives the relative vertical offset for any continuation lines. If the phrase is omitted, a value of 1 is assumed for integer-3 . Thus, by default, a line is continued onto the immediately following line. If a PAGE LIMIT clause is present in the RD, the value of integer-3 is used by the precompiler in calculating the (maximum) vertical size of the group to check that it will fit correctly into its assigned region of the page.
WRAP may be coded either (a) in an entry containing a LINE clause or (b) at a higher level having one or more LINE entries beneath it. This second possibility allows you to avoid repeating the same clause in several LINE entries.
Only relative COLUMN entries are allowed to cause wrap round. If a LINE entry has a WRAP clause, the COLUMN entries forming the description of the line must end in one or more relative COLUMN entries. Entries with absolute COLUMN numbers still cannot exceed the maximum line width.
A superfluous WRAP clause is not permitted. So the COLUMN entries (in particular the trailing relative COLUMN entries) must be such that the LINE LIMIT could be exceeded. (If this is not foreseeable at precompilation time, it will be assumed that this could happen at run time.)
If the WRAP clause is coded at a higher level with more than one LINE entry beneath it, it is sufficient if at least one of the LINE clauses obeys these rules. For example, it is permissible to code the WRAP clause at the 01-level, even if only one of LINE entries in the group can cause wrap round. However, in general any number - even all - the LINE entries in a report may be capable of causing wrap round.
The format b NO WRAP clause is allowed only at a level subordinate to a format a WRAP clause. The entry containing NO WRAP must represent more than one physical elementary printable field. No other nesting of the clause is permitted.
If the identifier form of the AFTER or TO phrase is used, the identifier's current value is used.
The following complete example shows how a variable number of error messages may be output:
The phrase AFTER COL 64 gives the last column that can be occupied by any field in the line. The phrase TO COL 36 gives the starting column for the wrap round. STEP 1 is assumed in default, so continuation is onto the next line. Note that the initial spacing implied by the "+ 3" of the first COLUMN clause on the new line is ignored.
As well the conditional case just described, where the continuation line appears in exceptional circumstances, it is possible (though less useful) for the wrap round to occur every time, as in this example:
which is exactly equivalent to:
Horizontal Fit Test
The "fit test" takes into account a field's variable length. By changing the PICTUREs in the previous example to make them variable length, we have the following, more common, situation:
The following sample output shows one of each possible outcome:
The longer names in this layout are a good example of the rare conditions that have to be allowed for, but which, without this special feature, often take up a disproportionate amount of programming effort.
If the containing group is a body group beginning with a relative LINE clause, the continuation lines are taken into account during the group's page-fit test. For
example, if only two lines are available for the printing of the last group in the preceding example, a new page would be started:
whereas in all the other instances the group would fit on the current page.
When an OCCURS clause or a multiple LINE clause is coded at the same level as WRAP, the WRAP clause applies separately to each occurrence .
NO WRAP indicates that the entries subject to NO WRAP must appear together in the same line. The horizontal "fit test" is therefore performed before the entire set of fields is output to ensure that they are not to split over a line boundary. (Compare NO MULTIPLE PAGE which does the same for the page boundary.) When an OCCURS clause is coded at the same level as NO WRAP, the NO WRAP clause applies separately to each occurrence. The following example lists names across several lines, keeping initials and surnames together: