MODULE 13 · MAINFRAME INTERNALS AND CAPSTONE · 2/10

Signed zoned decimal and overpunch

15 min30 XPExercise

You met zoned decimal (USAGE DISPLAY) numbers early on: one byte per digit. Now look at the bytes. On z/OS each EBCDIC digit byte has two halves (nibbles): a zone on the left and the digit on the right. The digit 7 is X'F7': zone F, digit 7.

A signed field has no byte for the sign. Instead the sign replaces the zone of the last byte:

Zone Meaning
C positive
D negative
F unsigned (treated as positive)

So PIC S9(3) holding -123 is X'F1F2D3'. This trick comes from punched cards, where the sign was an extra hole punched over the last digit, hence the name overpunch.

Why letters appear

X'D3' is not a digit character. In EBCDIC it is the letter L. So when you browse a dataset in ISPF, or when a file is converted to text and downloaded, signed amounts end in letters and braces:

Last digit 0 1 2 3 4 5 6 7 8 9
positive (Cx) { A B C D E F G H I
negative (Dx) } J K L M N O P Q R

0012345 with an unsigned last digit is +123.45 in S9(5)V99; 001234E is also +123.45; 001234N is -123.45. Memorise the table. You will see it in almost every file you look at.

GnuCOBOL is different

On an ASCII machine GnuCOBOL leaves positive values as plain digits and marks negatives with its own codes (p to y). Run this:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. OVERPNCH.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-Z         PIC S9(3) VALUE -123.
       01  WS-Z-BYTES   REDEFINES WS-Z PIC X(3).
       01  WS-TEXT      PIC X(7) VALUE "001234E".
       01  WS-AMT       REDEFINES WS-TEXT PIC S9(5)V99.
       PROCEDURE DIVISION.
           DISPLAY "WS-Z = " WS-Z ", STORED AS " WS-Z-BYTES
               ", HEX " FUNCTION HEX-OF(WS-Z)
           IF WS-AMT NUMERIC
               DISPLAY "001234E IS NUMERIC HERE"
           ELSE
               DISPLAY "001234E IS NOT NUMERIC HERE"
           END-IF
           STOP RUN.
WS-Z = -123, STORED AS 12s, HEX 313273
001234E IS NOT NUMERIC HERE

DISPLAY WS-Z edits the value for you (-123), but the stored bytes are 12s. And a mainframe-style 001234E is not valid zoned data to GnuCOBOL, so you must decode it yourself. That's the exercise: it is exactly the job you get when a mainframe extract lands on a Linux server.

The sign is part of the data

Move a signed field to a PIC X field and you move the overpunched byte, not a minus sign. For printing, always move numbers to an edited picture such as ----,--9.99.

On the job

When a downloaded file's amounts end in {, } or letters, don't "clean up" the letters: they are the sign. Ask whether the file should have been produced with SIGN IS LEADING SEPARATE (an explicit + or - byte), which is the safe format for exchanging numbers as text.

Your task

A mainframe extract of account adjustments was transferred to a Linux server as text. The amounts were PIC S9(5)V99 signed zoned decimal, so their last character is now an overpunch letter or brace. Decode them.

Input, DD name AMOUNTS, line sequential:

Field Picture Positions
AMT-ACCT X(6) 1–6
FILLER X 7
AMT-TEXT X(7), meaning S9(5)V99 with overpunch 8–14

The last character of AMT-TEXT gives the last digit and the sign: { A–I are +0 to +9, } J–R are -0 to -9, and a plain digit 0–9 is positive. The first six characters must be digits.

For each record display either the account, a space and the amount as ----,--9.99:

ACC004       -1.21

or, if the last character is not in the table or any of the first six is not a digit:

ACC006 INVALID 00100X1

After the last record:

VALID: 006  INVALID: 001
NET:          967.14

(NET is the sum of the valid amounts, ----,---,--9.99.)

Check your understanding

1. On z/OS, a PIC S9(3) DISPLAY field holds -123. What does it show as in a dataset browser?
2. What is the value of 00050} in a PIC S9(4)V99 field transferred from the mainframe?
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.