Special Topics


Contents:

Multiple Reports
Several Reports to One Physical File
Successive Reports
Alternating-Page-Format Reports
Concurrent Reports
Several Outputs From the Same RD
Developing User-Written Functions
The Need for Functions
How To Write a Function Routine
Sample COBOL Function Routine
Independent Report File Handlers
Introduction
Supplied File Handlers
User-Written File Handlers
Possible Uses of a File Handler
Using CODE
Actions of an Independent Report File Handler
File Handler LINKAGE Areas
Sample Independent Report File Handler

This part treats some more advanced or specialized topics.  The production of multiple reports, and the development of user-written extensions ( functions and file handlers) are also described.




Multiple Reports



COBOL Report Writer provides a means for producing either one physical file from several reports, or several physical files from one report description.  The following sections describe each case:


Several Reports to One Physical File

This is indicated when you write the clause

 
             REPORTS ARE report-name-1 report-name-2 ...

in the FD entry for the report file.  The different reports may be written either successively, alternately, or concurrently to the file.


Successive Reports

This describes the case when each successive report is processed through from INITIATE to the final TERMINATE and is then not accessed again:

 
           INITIATE report-name-1
           GENERATE report groups in report-name-1
           ...
           TERMINATE report-name-1
           INITIATE report-name-2
           GENERATE report groups in report-name-2
           ...
           TERMINATE report-name-2

This method is free of complications and has useful applications.  One example is the case where a report has a front section or a trailing section, too complex too describe as a REPORT HEADING or REPORT FOOTING:


   very complex "report heading"

< Instead of automatically using
< a REPORT HEADING, remember
< that this could be a report in
  its own right.
  
  

          body of report


  
   

   very complex "report footing"
< This might also be a
< separate "report".
  

The "Report Heading" might have several parts, and the "Report Footing" might have many complex parts, totals, etc.  You might instinctively try to describe this complex layout using a single RD, because it has been designed as a single report.  Remembering that a "report file" may be composed of several "logical reports", you now re-code the layout using three RDs:

 
       FD  print-file ...
           REPORTS ARE HEADING-REPORT, MAIN-REPORT, TRAILING-REPORT.
       ...
       RD  HEADING-REPORT
               ...
       RD  MAIN-REPORT
               ...
       RD  TRAILING-REPORT
               ...

and code the INITIATE, all the GENERATEs and the TERMINATE for each report in tandem.  Assuming that each RD has a PAGE clause, each report will begin on a new page, as required.

This example assumes that you have no page numbering in the "Report Heading" or "Report Footing", and that you start with a page number of one in the main report.  If you do require page numbering throughout, remember that each report has its own separate PAGE-COUNTER.  Assuming that the page numbers are to run in sequence throughout the report, you must carry forward the PAGE-COUNTER after each TERMINATE, as follows:

 
    PROCEDURE DIVISION.
        ...
        INITIATE HEADING-REPORT
        GENERATE heading-groups ...
        TERMINATE HEADING-REPORT
   *
        INITIATE MAIN-REPORT
        ADD 1 PAGE-COUNTER IN HEADING-REPORT GIVING PAGE-COUNTER IN MAIN-REPORT
        (process main report)
        TERMINATE MAIN-REPORT
   *
        INITIATE TRAILING-REPORT
        ADD 1 PAGE-COUNTER IN MAIN-REPORT GIVING PAGE-COUNTER IN TRAILING-REPORT
        GENERATE trailing-groups ...
        TERMINATE TRAILING-REPORT

 


Alternating-Page-Format Reports

You may encounter the case where a report consists of two or more alternating page formats, such as details of area A...summary page for area A details of area B...summary page for area B..., where each page format begins on a fresh page and has different PAGE HEADING, PAGE FOOTING and body groups from the others:

 Page Heading for detailed report
 AREA A

         DETAILED REPORT
< Detailed report headings are
< problem.


 . . . . . . . . . . . . . . . . . 
 . . . . . . . . . . . . . . . . . 
                 : 
 Page Heading for summary report
 SUMMARY FOR AREA A

          SUMMARY REPORT
< You cannot code this page as a
< CONTROL FOOTING because the
  page headings are completely
  different.
  
 Page Heading for detailed report
 AREA B

         DETAILED REPORT
< Here the page headings return
< to the first layout.


 . . . . . . . . . . . . . . . . . 
 . . . . . . . . . . . . . . . . . 
                 : 
 Page Heading for summary report
 SUMMARY FOR AREA A

          SUMMARY REPORT





When approaching this problem, keep in mind the points made under Successive Reports above.  This time, we keep both reports initiated.  (If not, the page numbering will return to 1 after each INITIATE, and there will be problems if, say, we want to produce grand totals at the end of the reports.)  The following is one possible solution.

 
FD  print-file ...
     REPORTS ARE DETAILED-REPORT, SUMMARY-REPORT.
     ...
 RD  DETAILED-REPORT
     ...
 RD  SUMMARY-REPORT
     ...
*
 PROCEDURE DIVISION.
     ...
     INITIATE DETAILED-REPORT, SUMMARY-REPORT
     obtain first input record
     PERFORM UNTIL end-of-file
          GENERATE detailed-groups ...
          IF   change in AREA code
               MOVE PAGE-COUNTER IN DETAILED-REPORT
                 TO PAGE-COUNTER IN SUMMARY-REPORT
               GENERATE summary-groups
               MOVE PAGE-COUNTER IN SUMMARY-REPORT
                 TO PAGE-COUNTER IN DETAILED-REPORT
          END-IF
          obtain next input-record
     END-PERFORM
     TERMINATE DETAILED-REPORT, SUMMARY-REPORT

(An alternative solution is to use an expression made up from both PAGE-COUNTERs, for example:

 
05  COL 100   "PAGE:".
05  COL + 2   PAGE-COUNTER IN DETAILED-REPORT +
              PAGE-COUNTER IN SUMMARY-REPORT - 1.)

Because you are not doing a TERMINATE and INITIATE on each occasion that you "switch reports", they will not necessarily always resume on a fresh page.  Consider each report separately and decide how you would make it resume on a fresh page if the other report were not there.  For example, you might begin after each "switch" with a GENERATE of a DETAIL group with a low absolute LINE number; or you might use the NEXT GROUP NEXT PAGE clause in a dummy CONTROL HEADING;  or you might simply code MOVE footing-integer TO LINE-COUNTER IN next-report-name before resuming.


Concurrent Reports

There are two quite unconnected cases to discuss here:

a.   One report built up from several alternating RD's.

Here, you GENERATE output via two or more RDs associated with the same report file without necessarily waiting for a page advance before switching from one report to another.  It can be difficult to use this method, because each report keeps its own LINE-COUNTER and control break information.  Each report will therefore act as though it alone had control of the page format.  Although no serious breakdown is likely at run time, you will have to take special steps to ensure that pages terminate at the correct point.  To do this, you will need to MOVE one LINE-COUNTER to another in much the same way that the PAGE-COUNTERs are dovetailed in the section on "Successive Reports" above.  If you specify the same control-ids in each report, remember that each possible control break will occur in each report separately, when it is GENERATEd.


b.   Distinct reports spooled to the same file.

Here, several reports are written to the same file but are distinguished by means of the CODE (see CODE Clause).  This technique was commonly used in the past when print data was spooled onto tape or disk.  Several reports could be written to the same spool file by marking the print records of each report with an identifying character, characters, or identifier of any length.  De-spooling software then passed through the spool file, each time selecting only those print records beginning with a certain identifying character.  (It was possible to sort the records, but this is usually much less efficient.)  As example, you might have had two reports:

 
FD  PRINT-FILE ...
     REPORTS ARE REPORT-A REPORT-B.
     ...
 RD  REPORT-A ...
     CODE IS "A" ...
*or: CODE IS mnemonic-name
*and put in SPECIAL-NAMES: "A" IS mnemonic-name
 01  ...
     ...
 RD  REPORT-B ...
     CODE IS "B" ...
 01  ...
     ...

The reports were both written to the same file, but you there was no problem in separating them as the reports eventually appeared as separate outputs, thanks to their distinguishing codes.  A utility to separate and print the physical reports is not provided as a part of the report writer software, and users who developed a utility program to handle the output produced by OS/VS and DOS/VS COBOL's built-in report writer with a CODE clause should use the same program to handle the output from report writer.


Several Outputs From the Same RD

There are two cases to be reviewed for this topic:

a.   Identical copies of the same physical report.

Following the ANS-74/85 standards, report writer does not allow you to assign your report to more than one file.  This is more restrictive than the ANS-68 standard used in OS/VS and DOS/VS COBOL, which allows up to two files.  If you require two or more identical copies of the same physical report, you should try to achieve this through Operating System commands, or you should write an  Independent Report File Handler (see 5.3) that executes a WRITE for each of several files for each report line.


b.   Different reports with similar formats going to different files.

In a program with several reports, you may find that two or more report layouts are identical, or nearly so, and you naturally want to avoid duplication of code.  The DUPLICATED clause is designed for this purpose.  The following diagram shows a case with three files.

                  +--- ------------------------+
                  |                           |
                  |   similar report format   |
                  |  (
one Report Description) |
                  |                           |
                  +---------------------------+
                  /            |              \
  +-----------------+  +-----------------+  +-----------------+
  |                 |  |                 |  |                 |
  | report number 1 |  | report number 2 |  | report number 3 |
  |                 |  |                 |  |                 |
  +-----------------+  +-----------------+  +-----------------+

Although the layouts are similar, the contents of the reports may be quite different (as distinct from case a where all output is simply printed twice).  The DUPLICATED clause (see Report Files) sets up the given number of separate report control areas, each with its own PAGE-COUNTER, LINE-COUNTER , totals, control break indicators, Page Buffer, etc.  They are distinguished by the value of the special register REPORT-NUMBER which is defined by report writer in every program that has a DUPLICATED clause.  You may "switch" output to your selected report by storing a value from 1 to the maximum number of duplicates in REPORT-NUMBER.  Output goes to only one of the reports at any given time.  Although there are several separate physical files, only one SELECT clause and one FD entry are coded, and one OPEN and CLOSE is executed.  Despite your own OPEN statement, a file is actually opened only when the report whose number is held in REPORT-NUMBER is first INITIATEd.

If REPORT-NUMBER is zero when the INITIATE is executed, all the reports are INITIATEd.  The CLOSE operation (not the TERMINATEs) closes all the files that were opened.  The value of REPORT-NUMBER is immaterial when you OPEN and CLOSE.  You may MOVE ZERO to REPORT-NUMBER and do a single TERMINATE.  This will TERMINATE all the reports that were INITIATEd.  If REPORT-NUMBER is not zero when a TERMINATE is executed, only the corresponding report is terminated.

The report layouts need not be identical in all respects.  You may vary the entries "present" from one report to the next by using the PRESENT WHEN clause, and you may vary the contents by the same means or by using SOURCE identifiers subscripted by REPORT-NUMBER.  The DETAIL groups may even be different for each of the reports, since you can of course choose at any time which DETAIL groups to GENERATE.  Therefore the DUPLICATED clause may still save you coding time even if there are notable differences in the layouts of the report groups.

At run time, report writer will vary the for each of your multiple print files by appending to it the two digits 01 (for the first file) up to nn for the last file, where nn is the integer in your DUPLICATED clause.  If you specify a DDname of more than six characters, characters 7 and 8 of your DDname are overwritten.  For example:

 
   SELECT FILEA ASSIGN TO LST  DUPLICATED 3 TIMES

expects your  to be LST01, LST02 and LST03, and

 
   SELECT...ASSIGN TO LISTINGF DUPLICATED 16 TIMES

expects your  to be LISTIN01 through LISTIN16.

The following sample of coding shows how these techniques are used:

 
FILE-CONTROL.
     SELECT REPORT-FILE ASSIGN TO PRINTF
     DUPLICATED 3 TIMES.
           ...
 FD  REPORT-FILE
     ...
     REPORT IS STOCK-REPORT.
 ...
 REPORT SECTION.
 RD  STOCK-REPORT ...  .
 01  STOCK-LINES  TYPE DE.
   03  LINE + 2.
     ...
*The following is a subheading that is different in each report:
     05  COL 120       PIC X(20)  SOURCE WS-DESCRIPTION (REPORT-NUMBER).
*The following line is not generated in report #1:
   03  LINE       ABSENT WHEN REPORT-NUMBER = 1.
     ...
 PROCEDURE DIVISION.
     ...
*Report file is opened only once
*even though it represents 3 potential files
     OPEN OUTPUT REPORT-FILE            *> intercepted by report writer
     ...
*If report #1 is required during this run:
     MOVE 1 TO REPORT-NUMBER
     INITIATE STOCK-REPORT
     ...
*and, in general, if report #n is required:
     MOVE n TO REPORT-NUMBER
     INITIATE STOCK-REPORT
     ...
*When output is sent to report #1, for example:
     MOVE 1 TO REPORT-NUMBER
     GENERATE STOCK-LINES
     ...
*and, in general, when output is sent to report #n:
     MOVE n TO REPORT-NUMBER
     GENERATE STOCK-LINES
     ...
*to terminate all of the 3 reports that may have been initiated:
     MOVE 0 TO REPORT-NUMBER
     TERMINATE STOCK-REPORT
     ...
*or, to terminate just report #1:
     MOVE 1 TO REPORT-NUMBER
     TERMINATE STOCK-REPORT
     ...
     CLOSE REPORT-FILE.

If you refer to LINE-COUNTER, PAGE-COUNTER, a total field, or any of the other special registers within the Report Control Area, the actual location accessed will be the one belonging to the report for which the most recent INITIATE, GENERATE, or TERMINATE was performed. For example, if you wish to reset PAGE-COUNTER in each of your reports in the multiple set, you should define a dummy DETAIL group (one having no LINEs) and code the following:

 
MOVE 1 TO REPORT-NUMBER
GENERATE DUMMY-GROUP           *>needed to make Report #1 current
MOVE 0 TO PAGE-COUNTER
MOVE 2 TO REPORT-NUMBER
GENERATE DUMMY-GROUP
  ... etc. ...

If you use a procedural statement, such as a MOVE, to store a value directly into a named field in one of your REPORT SECTION lines, the new contents will take effect for all the reports of the multiple set, because the report lines produced by report writer are shared by each of them.




Developing User-Written Functions




The Need for Functions

The FUNCTION clause, which is described from the user's point of view under 3.7 FUNCTION Clause, allows you to develop your own function routines as well as to use certain built-in functions, such as DAY, MDATE, and TIME.  A user-written function allows you to display report data in a way peculiar to your installation.

User-written functions are especially effective when needed in many separate programs, as they provide a standard way of displaying certain codes or other items of information peculiar to the user site.  Indeed a commitment to "think functionally" may greatly improve efficiency throughout a programming department.  To convince yourself of this, consider the following scenario, before the introduction of functions:

Many report programs require the programmer to code a table of descriptions or names directly into the Working-Storage of the program.  Perhaps at first only a few report programs of this type are written, so that, even when some extra codes are added to the table and all those programs have to be re-compiled, no one objects too strongly.

Suddenly a large number of new programs are written that require the same names.  Some programmers code the table from scratch; others prefer to take a copy from a working program.  Business conditions then change and many new codes are added to the table.  Dozens of programs have to be changed.  Any change requires retesting of whole suites of programs.  Each program has its own particular way of encoding the table, so an amendment becomes a major undertaking.  At the end of it, no one is absolutely sure that all the programs affected have been found and amended.

When the next major change becomes necessary, some one decides that from now on all the codes will be held in a static "table file".  New programs are guaranteed to be independent of the codes and names, but there is a penalty to be paid in each program, because of all the extra steps needed to OPEN, READ and CLOSE the file in the program.  Later, there might be a general change from traditional files to a database, so all the programs have to be amended again.

Through the use of functions from the outset, programs can be made independent of all these changes.  The program will be shorter and the programmer need not worry about how the report field is created.  Control over specification and change becomes more assured.


How To Write a Function Routine

As designer of a function routine, you have a free hand to transform the data in any desired way, provided that the print data that results fits within the limits of the print field described by the programmer in the associated PICTURE clause.

Most function routines are COBOL subprograms with a standard LINKAGE SECTION, but they may also be written in any programming language that can be CALLed by COBOL.  The use of COBOL normally prevents the number of parameters passed to the FUNCTION from being variable (a minor benefit).  Since they are "normal" programs, function routines may use any files or databases that are available to other programs, may CALL other subprograms, and may store intermediate results in their own Working-Storage.

The number of relevant characters returned in the output (report) field may vary, thus enabling the same function routine to handle different sizes and formats, for example "date" formats with different arrangements of day, month, and year.  The size and format of the user-coded parameters (if any) are usually prescribed by the function routine and cannot vary, unless the designer decides to specify an additional parameter to indicate which of a choice of formats the input is in.  All parameters are passed "by reference" so, although they normally pass data only into the function routine, they may also be used to pass updated data back to the user program.

The function routine is used in the program via the  FUNCTION Clause (see 3.7), and the programmer need not be aware of the precise mode of operation of the function routine.  The description of the built-in functions is also given in 3.7 - FUNCTION Clause.  User-written functions may be similarly specified and added to this publication in an appropriate place.

The program name of the function routine should be Rnxxxxxx, where xxxxxx is the mnemonic name of the function of no more than 6 alphanumeric characters and n is the number of parameters to the function.  For example, if the function is called COUNTY and takes one parameter, you must write a function module with the program-id: R1COUNTY otherwise.  If the same function has a variable number of parameters, separate function routines must be written (although they may all call a common subordinate routine).

The parameters to the function routine are as follows:

Parameter 1:      Function Control Area, consisting of:

    2 bytes binary:   number of user-coded parameters present in FUNCTION
                      clause, i.e. excluding internal parameters 1 and 2;
    2 bytes binary:   total size of field, in bytes, or, if field is
                      edited, its equivalent de-edited size;
    2 bytes binary:   size in bytes of parameter #1 of FUNCTION, if any
    2 bytes binary:   size in bytes of parameter #2 of FUNCTION, etc.

Parameter 2:      report field; if edited, de-edited intermediate field;

Parameters 3,4... (optional) parameters as defined in FUNCTION clause.


Sample COBOL Function Routine

 
IDENTIFICATION DIVISION.
 PROGRAM-ID.  R1DEPOT.
*
*COBOL Report Writer user function
*Converts internal depot code 'L', 'B', or 'N'
*to full name for printing in report
*Available report field sizes:
*  4 = short form ('LNDN', 'BHAM', 'NCSL', ETC.)
* 12 = long form ('LONDON', 'BIRMINGHAM', 'NEWCASTLE' ETC.)
*
*To use, write: FUNC DEPOT (DEPOT-CODE) instead of SOURCE...
*
*This function may be converted later to hold depot names in a
*file or database table without impact on the programs.
*
 ENVIRONMENT DIVISION.
 DATA DIVISION.
*
 WORKING-STORAGE SECTION.
 01  WS-FIELDS.
*table of short names
   03  SHORT-NAME-TAB        VALUE "LNDNBHAMNCSL????".
     05  SHORT-NAME          PIC X(4) OCCURS 4.
*table of long names
   03  LONG-NAME-TAB         VALUE
       "LONDON      BIRMINGHAM  NEWCASTLE   UNKNOWN     ".
     05  LONG-NAME           PIC X(12) OCCURS 4.
   03  W-DEPOT-NUMBER        PIC S9(4) COMP.
   03  W-PARAM-ERR           PIC X.
*
 LINKAGE SECTION.
*Param (1): Function Control Area
 01  L-FUNC-CTL.
*No. of parameters to function:
   03  L-PARAM-CNT           PIC S9(4) COMP.
*Length of output field in bytes:
   03  L-OP-LEN              PIC S9(4) COMP.
*Length of parameter in bytes:
   03  L-PM1-LEN             PIC S9(4) COMP.
*
*Param (2): output area
 01  L-OP-FLD.
   03  L-OP-CH               PIC X   OCCURS 1 TO 12
                             DEPENDING ON L-OP-LEN.
*Param (3): input depot code
 01  L-DEPOT-CODE            PIC X.
*
 PROCEDURE DIVISION USING L-FUNC-CTL, L-OP-FLD, L-DEPOT-CODE.
 FUNCTION-ENTRY.
     PERFORM PARAMETER-CHECK
     IF   W-PARAM-ERR = "N"
          PERFORM CONVERT-CODE.
 FUNCTION-EXIT.
     EXIT PROGRAM.
*Routine to check parameters:
 PARAMETER-CHECK.
     MOVE "N" TO W-PARAM-ERR
*Check correct parameter specification
     IF   L-PARAM-CNT NOT = 1
     OR   L-PM1-LEN NOT = 1
          DISPLAY
          "R1DEPOT ERROR CRW-651: INVALID PARAMETERS"
          MOVE "Y" TO W-PARAM-ERR.
*Check report field is correct size
     IF   L-OP-LEN NOT = 4 AND NOT = 12
          DISPLAY
          "R1DEPOT ERROR CRW-652: INVALID REPORT FIELD SIZE"
          MOVE "Y" TO W-PARAM-ERR.
*Routine to convert depot code:
 CONVERT-CODE.
*Check input depot code, convert to integer 1-3, or 4 if unknown
     IF   L-DEPOT-CODE = "L"
          MOVE 1 TO W-DEPOT-NUMBER
     ELSE IF   L-DEPOT-CODE = "B"
               MOVE 2 TO W-DEPOT-NUMBER
          ELSE IF   L-DEPOT-CODE = "N"
                    MOVE 3 TO W-DEPOT-NUMBER
               ELSE MOVE 4 TO W-DEPOT-NUMBER.
     IF   L-OP-LEN = 4
          MOVE SHORT-NAME (W-DEPOT-NUMBER) TO L-OP-FLD
     ELSE MOVE LONG-NAME (W-DEPOT-NUMBER) TO L-OP-FLD.




Independent Report File Handlers




Introduction

An Independent Report File Handler (or file handler) is a separately-compiled program routine that takes over all the functions of the normal COBOL OPEN-WRITE-CLOSE protocol for a particular report.  The source program, as written, is identical in all respects to a regular batch print program, except that the SELECT...ASSIGN clause for the file to which the report is directed carries the additional sub-clause MODE IS... (see Report Files), and that there may also be a CODE clause (see CODE Clause) in the RD.  (The MODE sub-clause can also be "forced" by default onto any report file does not have a MODE by an external option setting - see Installation and Operation.)

File handlers monitor the results of any i/o operations they perform and pass any error codes back in the FILE STATUS field in the usual way, or, if no FILE STATUS is specified, they display a suitable message and, if the error is irrecoverable, abort the run.

COBOL Report Writer comes with some built-in file handlers and these are listed below.  Any number of others may be written by users to similar standards.  File handlers can be written in COBOL or another language.


Supplied File Handlers

The following list explains the function of each of the built-in file handlers and gives the MODE mnemonic you require to invoke each.

MODE PRNT   Purpose:  basic printing.
This file handler performs the same basic print functions as when no file handler is used at all.  Unless you already specify a MODE clause, it will be used automatically when any of the following features is used:
 ¶   PAGE BUFFER clause in SELECT
 ¶   DUPLICATED clause in SELECT
 ¶   STYLE clause
 ¶   UPON option of INITIATE
 ¶   CODEs of unequal length for RDs of same file.
Effect of CODE:  Placed at start of print line, as in ANS standards.  It is output after any carriage control characters.


MODE NOPF   Purpose:  basic printing without using page feeds.
This file handler fills each page entirely using line feeds.
Effect of CODE:  Placed in print line after the carriage control.


MODE MODL   Purpose:  for use in a modular system.
This file handler may be used by more than one separately compiled program in a run unit.  Each program may thus write to the same report file.  See listing below.
Effect of CODE:  Placed in print line after the carriage control.

MODE MULT   Purpose:  write to more than one file simultaneously.
This file handler must be used if a program using a file handler requires to have more than one report file open simultaneously.  It is needed if the DUPLICATED phrase is used.
Effect of CODE:  Placed in print line after the carriage control.

MODE CHAN   Purpose:  make optimal use of any printer channels.
The channel positions are fed into the file handler at run time, as described in Installation and Operation.  The file handler automatically uses channel skips to get as near as possible to each target line.  The RD does not change.
Effect of CODE:  Placed in print line after the carriage control.

MODE DUPL   Purpose:  emulate OS/VS and DOS/VS COBOL's ability to write to two files simultaneously.
The file handler performs the OPEN, WRITE, CLOSE as appropriate for each file in turn.
Effect of CODE:  Placed in print line after the carriage control.

MODE NOCC   Purpose: print without any carriage control characters.  Blank lines are written as space lines.  This file handler is useful for small demonstrations that will be viewed on a screen rather than printed.
Effect of CODE:  Placed at start of print line.

MODE S370   Purpose: write lines using system-370 type carriage control characters.  This file handler may be used for compatibility with VisualAge COBOL's print format.
Effect of CODE:  Placed at start of print line.


User-Written File Handlers

An Independent Report File Handler is not usually developed as part of one program, but separately so that it can be used by all the report programs in a project.  Only a brief specification is normally required, similar to those in the table of built-in file handlers below.  Any application will then be able to use the file handler.

The file handler has a fixed LINKAGE SECTION, and the areas and their various locations are given in COBOL format below.  For use in a language other than COBOL, translate the data-names and PICTUREs as appropriate.

The program-name of the file handler is related to the name of the MODE mnemonic.  Full details are given in Operation and Installation.



Possible Uses of a File Handler

In this section we list some possible uses to which you might put a file handler.


Using COBOL Report Writer for Non-Report Output

Provided your program's "report lines" contain no COMPUTATIONAL entries, you might adapt your file handler to produce output which is not intended for printing but instead for passing on to another program.  Then, if you decide to ignore all LINE numbers, so that each "line" is another record irrespective of the "line advance", your file handler would simple do a WRITE without ADVANCING.

Output to Database

Your program may be required to send its printed output to a database rather than in a sequential file.

Private STYLEs

If the printer has advanced features that require special programming, you can designate certain STYLEs as PRIVATE. The processing of such STYLEs is then left to your file handler. Full details are in Installation and Operation.

Output to Multiple Files

Your file handler may write to several files simultaneously, as outlined above (see 5.1.3) and under MODE DUPL above.



Using CODE

In a "batch" report, the CODE is a "literal" prefixed to every print line.  However, with a file handler you can designate the CODE clause for the passing of any additional information from the program to the file handler.  Normally this is to control the output, rather than for output as part of the data.  For example, given the necessary hardware and software prerequisites, you might decide to develop a file handler, and use the CODE clause, as follows:

Your possible file handler:   Likely use of CODE:

Microfiche output   Key for fiche indexing.
Remote transmission   Identifier for remote printer.
Spooled restart system   Key, page number, etc., for restart.

The contents of the program's CODE operand appears in the file handler as the LINKAGE SECTION item L-RCA-CODE-VAL, as described later in this section.



Actions of an Independent Report File Handler

A file handler must perform certain mandatory housekeeping functions in order to execute correctly in combination with the report writer code.  However, the method by which the report data is physically output is left entirely to the file handler.

If the file handler may be required to service more than one report file or INITIATEd report simultaneously, or be required to be usable by more than one program simultaneously, it should store its intermediate results in the File Control Area or Report Control Area, where certain locations have been reserved for discretionary use by the file handler.

The following are the mandatory housekeeping actions that must be performed by every file handler.  The standard locations referred to are described later in this section.

1.   If the location L-FCA-ACT-IND is anything other than "0" or "9", "OPEN" the report "file".  The file handler may interpret the OPEN function and the nature of the "file" in any way it wishes.  The value of L-FCA-ACT-IND indicates the type of OPEN required (OUTPUT, EXTEND, or other).

2.   If the location L-RCA-ACT-IND is "6", "INITIATE" the report.  The file handler may perform the INITIATE action in any way it wishes.

3.   If there is data to output, indicated by the field L-PRC-BYTE-CNT being non-zero, "print" the data.  The exact nature of the "printing" activity is left entirely to the file handler and may differ widely from a "batch" WRITE statement.  The following locations will be needed to accomplish this:

L-RCA-VERT-POSN contains the current vertical position or zero.  If it is zero the file handler should execute a "form feed".  This action should be omitted if L-RCA-PAGE-LIM is zero, indicating that the report is not divided into pages.

L-FCA-SUPP-PFD, if set to 1, indicates that the program has a FIRST PAGE NO ADVANCING clause in the SELECT...ASSIGN.  If so, the "form feed" is not done and instead the current position is assumed to be "line 1".  It is cleared automatically by the control routine.

L-RCA-LINE-CNTR contains the target vertical position.  By subtracting L-RCA-VERT-POSN from this, you obtain the distance to be advanced.

4.   If the location L-RCA-ACT-IND is "8", "TERMINATE" the report.  The file handler may perform the TERMINATE action in any way it wishes.

5.   If the location L-FCA-ACT-IND is "9", "CLOSE" the report "file".  The file handler may interpret the CLOSE function in any way it wishes.

By convention, there will never be more than one action from the possibilities OPEN, INITIATE, "print", TERMINATE, and CLOSE on any entry.



File Handler LINKAGE Areas

All the information required by the file handler is passed to it via optional user parameters and three standard LINKAGE areas, of which source copies are provided with this product.


Optional Leading Parameters:  User-Defined Parameters

There may be any number of parameters at the start of the LINKAGE SECTION pre-determined by the user and specified through the USING phrase of the MODE clause.  See Report Files for a description of this phrase.

Parameter 1:  File Control Area

The File Control Area contains information relating to the current report file.  A File Control Area is set up for each report file that has a MODE clause.

 
01  L-FCA-CNTRL-AREA.

*Maximum length in bytes of CODEs for this file.
*= 0 if CODE clause is not present for any reports in file.
   03  L-FCA-CODE-LEN        PIC S9(4) COMP.

*Maximum record length in bytes for File.
   03  L-FCA-REC-LEN         PIC S9(4) COMP.

*Action indicator byte.
*Action performed is open to interpretation by the designer.
*"0" = no action against file
*"1" = file to be opened output
*"2" = file to be opened extend
*"5" = file to be opened in irregular manner
*"9" = file to be closed
   03  L-FCA-ACT-IND         PIC X.

*File status indicator.
*Initial value = low-values (hex '00')
*"0" = file not opened
*"1" = file opened output
*"2" = file opened extend
*"5" = file opened in irregular manner
*"9" = file closed
   03  L-FCA-STAT-IND        PIC X.

*Count of reports initiated for this file.
*Incremented by 1 on INITIATE, decremented by 1 on TERMINATE;
*initially zero, must never become negative;
*used to warn on CLOSE if some report(s) still initiated
   03  L-FCA-REPS-INT        PIC S9(4) COMP.

*MODE mnemonic name:
*up to 4 characters (padded with spaces) from the MODE clause
   03  L-FCA-MODE-MNEM       PIC X(4).

*File Status:
*If L-FCA-FS-IND (below) = "1", file handler control routine will
*always pass back any file status here without abandoning the run;
*Otherwise, file handler control routine will abandon the run with
*an error message if a serious error is indicated in File Status.
   03  L-FCA-STATUS          PIC XX.

*File Status indicator: set if SELECT has a FILE STATUS clause.
   03  L-FCA-FS-IND          PIC X.
*Unassigned:
   03  FILLER                PIC X.

*Locations reserved for communication between file handler
*and report writer:
*integer of DUPLICATED clause if present; zero if no such clause
   03  L-FCA-DUP-FACT        PIC S9(4) COMP.

*Recording mode = "F", "V", "U", "S" or space if not specified
*taken from RECORDING MODE clause of the FD;
*may be taken into account or ignored by the file handler
*(report record is always variable-length; (see 2.2.3))
   03  L-FCA-REC-MODE        PIC X.

*Indicator set = "1" if PAGE BUFFER clause present:
   03  L-FCA-PBUF-IND        PIC X.

*First four characters of file name:
   03  L-FCA-FILE-PFIX       PIC X(4).

*Locations reserved for use by file-handler:
*Address of block of DUPLICATED FCA's, if applicable
   03  L-FCA-DUP-ADR         PIC X(4).
*General-purpose location used as by file handler
   03  L-FCA-GEN-LOCN        PIC S9(4) COMP.
*Suppress page feed indicator:
*Set = "1" if next page feed (always the first since OPEN) is
*to be ignored.
   03  L-FCA-SUPP-PFD        PIC X.
*Data-written indicator:
*Set = "1" if something has been written to the file
   03  L-FCA-WRITE-IND       PIC X.
*Unassigned:
   03  FILLER                PIC X(4).
*Reserved for general use by File Handler:
   03  L-FCA-WORK-AREA       PIC X(20).

*DDname from SELECT...ASSIGN statement:
*May be altered by user program by storing value in
*field DDNAME in File Control Area
   03  L-FCA-DDNAME          PIC X(8).
*Alternative details of file name:
   03  L-FCA-FN-BLK REDEFINES L-FCA-DDNAME.
*Length in bytes of file-name
     05  L-FCA-FN-LEN        PIC S9(4) COMP.
*Binary zero:
     05  L-FCA-FN-SLACK      PIC X.
     05  FILLER              PIC X.
*Address of file-name
     05  L-FCA-FN-ADR        PIC X(4).

*End of File Control Area

 


Parameter 2:  Report Control Area

The Report Control Area is set up by the Precompiler for each report that is directed to a file that has a MODE clause.  In the user program, the Report Control Area is identified by the report-name.

 
01  L-RCA-CNTRL-AREA.

*PAGE-COUNTER, referred to in program as
*PAGE-COUNTER [IN report-name]:
   03  L-RCA-PAGE-CNTR       PIC S9(9) COMP.

*LINE-COUNTER, referred to in program as
*LINE-COUNTER [IN report-name]
*Shows the desired position for this report line:
   03  L-RCA-LINE-CNTR       PIC S9(9) COMP.

*Vertical position pointer.
*Shows the actual current position vertically on the page.
*diff. between this field and LINE-COUNTER gives desired advance;
*If this location is zero, a form feed is required first.
   03  L-RCA-VERT-POSN       PIC S9(9) COMP.

*Line byte count override;
*Used internally only.  Will = -1 in file handler.
   03  L-RCA-LINE-SIZE       PIC S9(4) COMP.

*Line Limit; i.e. the logical size of the report line
*from the LINE LIMIT clause in the RD, or its default:
   03  L-RCA-LINE-LMT        PIC S9(4) COMP.

*Action indicator byte:
*"0" = no change to report status
*"6" = report to be initiated
*"7"   reserved
*"8" = report to be terminated
   03  L-RCA-ACT-IND         PIC X.

*Report status indicator:
*"0" = report never initiated
*"6" = report initiated
*"8" = report terminated
   03  L-RCA-STAT-IND        PIC X.

*Report-name from RD statement:
   03  L-RCA-REP-NAME        PIC X(30).

*Print record format indicator: always = "0"
   03  L-RCA-PRT-FMT         PIC X.
*Line column width override: (1 byte binary held as character)
   03  L-RCA-COL-WIDTH       PIC X.

*Page Limit from PAGE LIMIT clause RD; zero if no PAGE clause.
   03  L-RCA-PAGE-LIM        PIC S9(4) COMP.

*Length of CODE, or zero if no CODE clause.
*The length of the CODE is determined from the length of the CODE
*"literal" or, if the "identifier" form of CODE clause is used,
*from the difference between the record length of the report file
*(as given in the RECORD or BLOCK CONTAINS clause of the FD)
*and the LINE LIMIT (or its default value),
*allowing for the normal carriage control characters.
   03  L-RCA-CODE-LEN        PIC S9(4) COMP.

*Error flag: zero = no error.
*May be set by file handler to non-zero value representing a
*standard error condition for reporting via a subroutine.
*If it is given a value which does not correspond with a known
*error message, the message UNKNOWN ERROR TYPE will be output
*together with information that usually accompanies any message.
   03  L-RCA-ERR-FLG         PIC S9(4) COMP.

*Error code detected by file handler:
   03  L-RCA-FH-ERR          PIC S9(4) COMP.

*Report Number from REPORT-NUMBER location
*zero if DUPLICATED clause not in use.
   03  L-RCA-REP-NUM         PIC S9(4) COMP.

*Location reserved for future communication between file handler
*and report writer.
   03  L-RCA-COMM-AREA       PIC X(8).

*Location reserved for internal use (not by file handler):
*Data items used by Page Buffer:
*Current margin offset established by SET COLUMN (1 = no margin).
   03  L-RCA-MARG            PIC S9(4) COMP.

*Forced absolute line number set up by SET LINE TO integer.
   03  L-RCA-ABS-LNO         PIC S9(4) COMP.

*Indicator set to "H" "HOLD" status, otherwise space.
   03  L-RCA-HOLD-IND        PIC X.

*General locations used by file handlers:
   03  FILLER                PIC X(11).

*Data items used by Page Buffer: (not required by file handler)
*Current physical position;
   03  L-RCA-PHYS-POSN       PIC S9(4) COMP.

*Lowest line no. having line buffered.
   03  L-RCA-STL-LOW         PIC S9(4) COMP.

*Highest line no. having line buffered.
   03  L-RCA-STL-HIGH        PIC S9(4) COMP.

*Maximum value permitted for LINE-COUNTER.
   03  L-RCA-MAX-LCT         PIC S9(4) COMP.

*Maximum physical size in bytes of "line" of data;
*this is the largest value that can ever be held in "byte count"
*(L-PRC-BYTE-CNT) of any print line.
*It differs from the line limit (L-RCA-LINE-LMT) in that
*(a) the line limit is a maximum for checking purposes only and
*may never be attained in any actual line of the report,
*(b) lines may contain formatting characters that do not occupy
*a column of print, e.g.
*start- and end-sequence of a "style" (underline, bold etc.)
*shift out and shift in characters used by Kanjii (DBCS)
   03  L-RCA-BYTE-LMT        PIC S9(4) COMP.
*Number of purely formatting characters override; if non-zero, the
*value (L-PRC-BYTE-CNT - L-RCA-FMT-CNT) overrides L-PRC-END-COL;
*it must always be cleared by file handler.
   03  L-RCA-FMT-CNT         PIC S9(4) COMP.
*Indicators, for general use by file handler.
   03  L-RCA-WORK-IND        PIC X OCCURS 4.

*Code Value; zero length if no CODE clause in RD
*initial value set from CODE clause.
*May be referred to in user program as CODE-VALUE [IN report-name]
   03  L-RCA-CODE-VAL.
     05  L-RCA-CODE-CHA      PIC X
         OCCURS 0 TO 4095 TIMES DEPENDING ON L-RCA-CODE-LEN.
*End of report control area.

 


Parameter 3:  Report Data

This parameter contains the data to be written.  For OPEN, INITIATE, TERMINATE and CLOSE operations, this parameter is a dummy with a value of zero in the counter L-PRC-BYTE-CNT.  The number of bytes to be written may be reduced to the value in L-RCA-LINE-SIZE when it is non-negative.

 
01  L-PRC-PRINT-REC.

*Physical byte count, not including this 4-byte header;
*will be zero when no data is to be output;
*gives no. of bytes to be written, unless overridden by
*L-RCA-LINE-SIZE set non-negative.
   03  L-PRC-BYTE-CNT        PIC S9(4) COMP.

   03  L-PRC-HEAD.
*Indicator bits, layout is as follows:
*bit 0-3: unused
*bit 4: set if data contains unresolved STYLE sequence(s)
*bit 5: set if data consists only of formatting (STYLE) characters
*bit 6: reserved
*bit 7: set if print data must be flushed to spaces.
*2nd byte is reserved.
     05  L-PRC-HEAD-BYTES    PIC S9(4) COMP.
*Data to be written;
   03  L-PRC-DATA.
     05  L-PRC-DATA-CHA      PIC X
         OCCURS 0 TO 256 TIMES DEPENDING ON L-PRC-BYTE-CNT.



Sample Independent Report File Handler

The following is the complete code of the standard MODL file handler (used for writing to a single report file from a modular system).  This file handler is one of the simplest, and so it may be used as a model for your own user-written file handlers, which will require almost all the code that follows, except perhaps for the incrementing and decrementing of the "nest depth" (W-OPEN-NEST) which is peculiar to this file handler.

At least one file handler is supplied in source form with this product, giving you a machine-readable copy of most of this coding.

 
IDENTIFICATION DIVISION.
*
*Independent Report Writer file handler for use in modular program
*
*Purpose:
*    Used when several separately-compiled modules need to access
*    the same report file without continually opening and closing.
*    This file handler does not currently handle more than 1 file.
*
*Method of use:
*    1.  The control program does one OPEN at start of processing
*        and one CLOSE at very end of all processing.
*        (To satisfy the syntax it should have a minimal
*        REPORT SECTION which is not used.)
*    2.  Each subprogram including control module has an FD
*        & does OPEN, some GENERATEs and CLOSE each time it is
*        CALLed, as though it were the only module using the file.
*
*    This file handler ignores all "nested" OPENs and CLOSEs.
*    Typical sequence of operations:
*
*    a.  Control program does OPEN OUTPUT which is actioned.
*    b.  Subprogram does OPEN which is ignored.
*    c.  Subprogram does INITIATE, several GENERATE's & TERMINATE.
*    d.  Subprogram does CLOSE which is ignored.
*    e.  Many other subprogram CALLs occur in same way.
*    f.  Control program does CLOSE which is actioned.
*
*    Subprograms have to do the (dummy) OPEN and CLOSE as Report
*    Writer requires that every program be logically complete.

 ENVIRONMENT DIVISION.
*
 INPUT-OUTPUT SECTION.
 FILE-CONTROL.
     SELECT PRINT-FILE
* is always overwritten by name specified in program
          ASSIGN TO RPFILE
          FILE STATUS IS W-FCA-STATUS.

 DATA DIVISION.
 FILE SECTION.
 FD  PRINT-FILE
     LABEL RECORDS STANDARD.
*THIS FILE MAY ALSO BE DESIGNATED "RECORDING MODE V"
 01  F-PRINT-RECORD.
     05  F-PRINT-DATA.
       07  F-PRINT-CHAR            PIC X  OCCURS 512.

 WORKING-STORAGE SECTION.
*General locations:
 01  WS-GENERAL.
     05  W-FEED                    PIC S9(4) COMP.
*This location contains the "nest" level of OPEN/CLOSE statements:
     05  W-OPEN-NEST               PIC S9(4) COMP VALUE ZERO.
*Pointer to record data:
     05  W-PTR                     PIC S9(4) COMP.
*Indicator set = "Y" if a the given line of data has been printed:
     05  W-DATA-PRINTED            PIC X.
*Indicator set = "1" if an error occurs on writing.
     05  W-PRINT-ERROR             PIC X.
*File status:
     05  W-FCA-STATUS              PIC XX.

*Standard Linkage:
 LINKAGE SECTION.

*Parameter 1: File Control Area
      COPY RWFCACOM.

*Parameter 2: Report Control Area
      COPY RWRCACOM.

*Parameter 3: Print Line
      COPY RWPLNCOM.

 PROCEDURE DIVISION USING   L-FCA-CNTRL-AREA
                            L-RCA-CNTRL-AREA
                            L-PRC-PRINT-REC.
*
 FILE-HANDLER-CONTROL SECTION.
 FHC-ENTRY.
*Assume successful operation:
     MOVE "00" TO W-FCA-STATUS
*Open file if indicated:
     IF   L-FCA-ACT-IND > "0" AND < "9"
          PERFORM OPEN-FILE.
*Initiate report if indicated:
     IF   L-RCA-ACT-IND = "6"
          PERFORM INITIATE-REPORT.
*Print data if any data present:
     IF   L-PRC-BYTE-CNT NOT = 0
          PERFORM PRINT-DATA.
*Terminate report if indicated:
     IF   L-RCA-ACT-IND = "8"
          PERFORM TERMINATE-REPORT.
*Close file if indicated:
     IF   L-FCA-ACT-IND = "9"
          PERFORM CLOSE-FILE.
     MOVE W-FCA-STATUS TO L-FCA-STATUS.
 FHC-EXIT.
     EXIT PROGRAM.

*Main sections to print the data line.
*
 PRINT-DATA SECTION.
 PDA-ENTRY.
*check not too many characters for print line:
     IF   L-PRC-BYTE-CNT > 512
          DISPLAY "CRFHMODL Error: Line too long - truncated".
     MOVE "N" TO W-DATA-PRINTED
*If vertical position is zero in paged report, page feed required:
     IF   L-RCA-VERT-POSN = 0
     AND  L-RCA-PAGE-LIM NOT = 0
     AND  W-PRINT-ERROR = "0"
*If FIRST PAGE NO ADVANCING was coded in SELECT statement
*omit first page advance (this ind. is reset by control s/r)
          IF   L-FCA-SUPP-PFD = "1"
               MOVE 1 TO L-RCA-VERT-POSN
          ELSE PERFORM TOP-OF-PAGE.
*Now write data after advancing required distance, unless it was
*written on line 1 when we advanced to top of page:
     IF   W-DATA-PRINTED = "N"
     AND  W-PRINT-ERROR = 0
          PERFORM AFTER-ADVANCING.

*Routine to print at top-of-page.
 TOP-OF-PAGE SECTION.
 TOP-ENTRY.
*If LINE-COUNTER = 1 we can print data at top-of-form,
*otherwise we print blank lines first;
     IF   L-RCA-LINE-CNTR > 1
          MOVE SPACES TO F-PRINT-DATA
     ELSE PERFORM FILL-RECORD
          MOVE "Y" TO W-DATA-PRINTED.
     WRITE F-PRINT-RECORD AFTER ADVANCING PAGE
*If bad File Status, set indicator to prevent further writing
*in case user program has FILE STATUS which is not exemined.
     IF   L-FCA-STATUS NOT = "00"
          MOVE "1" TO W-PRINT-ERROR.
     MOVE 1 TO L-RCA-VERT-POSN.

*Routine to print with appropriate advance (if any)
 AFTER-ADVANCING SECTION.
 ADV-ENTRY.
     PERFORM FILL-RECORD
     SUBTRACT L-RCA-VERT-POSN FROM L-RCA-LINE-CNTR GIVING W-FEED
     WRITE F-PRINT-RECORD AFTER ADVANCING W-FEED.
     IF   L-FCA-STATUS NOT = "00"
          MOVE "1" TO W-PRINT-ERROR.

*Move data into record, allowing fir possible CODE
 FILL-RECORD SECTION.
 FLR-ENTRY.
     IF   L-RCA-CODE-LEN = 0
     AND  L-RCA-MARG NOT > 1
          MOVE L-PRC-DATA TO F-PRINT-RECORD
     ELSE MOVE 1 TO W-PTR
          IF   L-RCA-CODE-LEN > 0
               MOVE L-RCA-CODE-VAL TO F-PRINT-RECORD
               ADD L-RCA-CODE-LEN TO W-PTR
          ELSE MOVE SPACES TO F-PRINT-RECORD
          END-IF
          IF   L-RCA-MARG > 0
               ADD L-RCA-MARG TO W-PTR
               SUBTRACT 1 FROM W-PTR
          END-IF
          STRING L-PRC-DATA DELIMITED BY SIZE INTO F-PRINT-RECORD
               WITH POINTER W-PTR.

*OPEN the report file
 OPEN-FILE SECTION.
 OPF-ENTRY.
*If OPEN not OUTPUT or EXTEND, signal error 44 and assume OUTPUT:
     IF   L-FCA-ACT-IND = "5"
          MOVE 44 TO L-RCA-ERR-FLG
          MOVE "1" TO L-FCA-ACT-IND.
*Does not really OPEN the file if the OPEN is "nested".
     IF   W-OPEN-NEST = 0
*Get name of print file
          IF   RETURN-CODE = 0
*OPEN OUTPUT or EXTEND, depending on the Action Indicator.
               IF   L-FCA-ACT-IND = "1"
                    OPEN OUTPUT PRINT-FILE
               ELSE OPEN EXTEND PRINT-FILE
               END-IF
          END-IF
          IF   L-FCA-STATUS NOT = "00"
               MOVE "1" TO W-PRINT-ERROR.
*Increment nest level:
     ADD 1 TO W-OPEN-NEST.

*Initiate the report
 INITIATE-REPORT SECTION.
 INT-ENTRY.
*In this section we do any action consistent with INITIATing
*the report.  In this routine nothing need be done.

*Terminate the report
 TERMINATE-REPORT SECTION.
 TRM-ENTRY.
*In this section we do any action consistent with TERMINATing
*the report.  In this routine nothing need be done.

*Close the report file
 CLOSE-FILE SECTION.
 CLF-ENTRY.
*Does not really CLOSE the file if the CLOSE is "nested".
     SUBTRACT 1 FROM W-OPEN-NEST
     IF   W-OPEN-NEST = 0
          CLOSE PRINT-FILE.
     MOVE "0" TO W-PRINT-ERROR.
*End of file handler.