Copybooks and COPY REPLACING
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 itsLINKAGE 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:
- Replace the two placeholder records with the copybook: prefix
OLDforOLD-FILEandNEWforNEW-FILE. -
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