MODULE 11 · SUBPROGRAMS AND COPYBOOKS · 7/8

Copybooks and COPY REPLACING

16 min30 XPExercise

Every program that touches the customer master needs the same 45-byte record layout. Every program that calls CALCVAT needs the same four parameters. Typing those by hand in each program is how you get the field-size mismatches you saw earlier in this module. The fix is a copybook: a piece of source kept in its own member and pulled in with COPY.

COPY

       FD  CUST-FILE.
       COPY CUSTREC.

COPY is a compiler-directing statement. Before compiling, the compiler replaces it with the text of member CUSTREC, and the compiled program is exactly as if you had typed the lines yourself. Nothing happens at run time. On z/OS the compiler looks for the member in the libraries on the SYSLIB DD of the compile job. If it isn't there you get a compile error, not a run-time one; GnuCOBOL says ADDRRX: No such file or directory for a missing COPY ADDRRX.

Copybooks usually hold:

  • record layouts for files, so every reader and writer agrees;
  • parameter lists for subprograms: the caller COPYs it into WORKING-STORAGE, the subprogram into its LINKAGE SECTION;
  • shared constants, error-message tables and 88-level status codes.

Change a copybook and every program that COPYs it has to be recompiled before the change reaches it. Shop tools track which programs use which copybooks for exactly this reason.

COPY ... REPLACING

Often you need the same layout twice in one program: yesterday's record and today's, a billing address and a shipping address. Two copies with the same field names would be ambiguous, so the copybook is written with a placeholder tag, and each COPY swaps in a different prefix. Here is copybook ADDRREC:

      * ADDRREC - POSTAL ADDRESS, 40 BYTES
       01  :PFX:-ADDRESS.
           05  :PFX:-STREET     PIC X(20).
           05  :PFX:-TOWN       PIC X(12).
           05  :PFX:-POSTCODE   PIC X(8).

and a program that uses it twice:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. ORDADDR.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       COPY ADDRREC REPLACING ==:PFX:== BY ==BILL==.
       COPY ADDRREC REPLACING ==:PFX:== BY ==SHIP==.
       PROCEDURE DIVISION.
           MOVE "12 QUAY STREET" TO BILL-STREET
           MOVE "GALWAY"         TO BILL-TOWN
           MOVE BILL-ADDRESS     TO SHIP-ADDRESS
           MOVE "CORK"           TO SHIP-TOWN
           DISPLAY "BILL TO: " BILL-TOWN " SHIP TO: " SHIP-TOWN
           DISPLAY "RECORD LENGTH: " FUNCTION LENGTH(SHIP-ADDRESS)
           STOP RUN.
BILL TO: GALWAY       SHIP TO: CORK
RECORD LENGTH: 40

The first COPY produces BILL-ADDRESS, BILL-STREET and so on; the second produces the SHIP- set.

==...== delimits pseudo-text: the text to find and the text to put in its place. Pseudo-text matches whole COBOL words, never part of a word. If the copybook said CUST-ID, then REPLACING ==CUST== BY ==OLD== would change nothing, because CUST-ID is one word. Colons, however, are separators, so :PFX:-STREET is the tag :PFX: followed by -STREET, and the tag can be replaced on its own. That is why the :PFX: (or :TAG:) convention exists. It is only a convention: any name in colons works as long as the copybook and the REPLACING agree.

REPLACING can list several pairs, and the replacement can be longer or shorter than the tag:

       COPY ADDRREC REPLACING ==:PFX:== BY ==WS-HOME==.

Copybooks and nested programs

Each program in a source file has its own data, so a nested subprogram that needs a layout COPYs it into its own LINKAGE SECTION, even when the outer program has already COPYed it into WORKING-STORAGE.

On the job

Before writing any record layout, search the copybook library. If a layout for the file exists, use it; if you write your own, your program breaks silently the day someone adds a field to the official one. Most shops also forbid changing a copybook without checking every program that COPYs it, and their change tools can list those programs.

Your task

Each night the bank compares yesterday's customer master with today's and reports what changed. Both files hold the same customers in the same order, and both use the layout in the shared copybook CUSTREC:

       01  :PFX:-REC.
           05  :PFX:-ID         PIC X(6).
           05  :PFX:-NAME       PIC X(20).
           05  :PFX:-TOWN       PIC X(12).
           05  :PFX:-LIMIT      PIC 9(6).
           05  :PFX:-STATUS     PIC X.
DD name Contents
OLDCUST yesterday's master, line sequential
NEWCUST today's master, line sequential

In CUSTDIFF:

  1. Replace the two placeholder records with the copybook: prefix OLD for OLD-FILE and NEW for NEW-FILE.
  2. In 2000-COMPARE, check the fields in the order name, town, limit, status and display one line per change:

    C00002 TOWN CHANGED C00003 LIMIT 010000 -> 007500 C00003 STATUS A -> S

Name and town changes print <id> NAME CHANGED / <id> TOWN CHANGED. Limit and status show old and new values as above. 3. Count a customer in WS-CHANGED once if anything changed (SET CUST-CHANGED TO TRUE).

The last line is written for you:

COMPARED 004 CHANGED 002

Check your understanding

1. When does COPY take effect?
2. A copybook defines CUST-ID. Does COPY ... REPLACING ==CUST== BY ==OLD== produce OLD-ID?
3. You change a copybook's layout. Which programs must be recompiled?
fixed format
Run your program to see its output here. The first visible test's input and datasets are used.
Submit to grade your program against every test.