Mainframe Path Start learning free
Core12 min readLesson 3 of 3

ON-units, file I/O and running PL/I on z/OS

PL/I reports events such as end of file, bad data and division by zero as conditions, and you decide what happens with ON-units. Files are read and written with record or stream I/O, and programs are compiled, bound and run under Language Environment much like COBOL.

Conditions and ON-units

When something notable happens, PL/I raises a condition. If you have established an ON-unit for it, that code runs; if not, the language's default action applies. This is PL/I's built-in error handling, decades older than try/catch in other languages.

ConditionRaised whenDefault if no ON-unit
ENDFILE(file)A READ or GET finds no more dataRaises ERROR
CONVERSIONCharacter data cannot be converted, for example letters into a numberRaises ERROR
ZERODIVIDEDivision by zero in fixed or floating arithmeticRaises ERROR
SIZEA value is too big for its target; disabled unless you enable itRaises ERROR when enabled
SUBSCRIPTRANGEA subscript is outside the array bounds; disabled unless enabledRaises ERROR when enabled
ERRORAny serious error, including the defaults aboveMessage, then the program ends
Common ON-units (illustrative)
 DCL EOF BIT(1) INIT('0'B);
 ON ENDFILE(INFILE) EOF = '1'B;

 ON CONVERSION BEGIN;
   PUT SKIP LIST('BAD NUMERIC DATA:', ONSOURCE());
   BAD_COUNT = BAD_COUNT + 1;
   GO TO NEXT_RECORD;
 END;

 ON ERROR BEGIN;
   ON ERROR SYSTEM;
   PUT SKIP LIST('UNEXPECTED ERROR, ONCODE', ONCODE());
   CALL PLIDUMP('TFC');
 END;

Record I/O

Record I/O moves whole records without conversion, the usual choice for batch files. The file name in the program is matched to a DD statement of the same name in the JCL, unless the TITLE option names a different DD.

A read loop with record I/O (illustrative)
 DCL INFILE  FILE RECORD INPUT;
 DCL OUTFILE FILE RECORD OUTPUT;
 DCL INREC   CHAR(80);

 OPEN FILE(INFILE), FILE(OUTFILE);
 READ FILE(INFILE) INTO(INREC);
 DO WHILE (EOF = '0'B);
   CALL PROCESS(INREC);
   WRITE FILE(OUTFILE) FROM(INREC);
   READ FILE(INFILE) INTO(INREC);
 END;
 CLOSE FILE(INFILE), FILE(OUTFILE);

PL/I also supports keyed access to VSAM files with KEY and KEYFROM. The KEY condition is raised for problems such as a record not found.

Stream I/O

Stream I/O treats a file as a stream of characters and converts values as it reads or writes. PUT LIST writes values with default formatting; PUT EDIT uses explicit formats such as A(20) for characters and F(9,2) for a fixed number. It is convenient for reports and SYSPRINT diagnostics, but slower than record I/O for big files.

Compiling and running under z/OS

From source to running program
SourcePDS member
CompileEnterprise PL/I
Bindload module
RunJCL, under LE

PL/I for COBOL maintainers

COBOLPL/I
Divisions, WORKING-STORAGEDECLAREs inside each block
PERFORM UNTILDO WHILE / DO UNTIL
EVALUATESELECT / WHEN / OTHERWISE
FILE STATUS checksON-units such as ENDFILE, KEY, UNDEFINEDFILE
OCCURSArray bounds after the name
CALL ... USINGCALL name(arguments)

Common mistakes

Swallowing errors in ON-units

An ON-unit that skips bad data without counting or reporting it hides real problems. Log, count and set a return code.

No ENDFILE ON-unit

Without one, reaching end of file raises ERROR and the program ends abnormally. Establish ON ENDFILE before the first READ.

Starting code in column 1

With the default margins, column 1 is not read as source. Indent code by at least one column.

What you will see at work

Key terms

Check your understanding.
Take this lesson's quiz and save your progress. Free.

Take the lesson quiz
← PL/I data types, structures and built-in functionsBack to PL/I fundamentals