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.
| Condition | Raised when | Default if no ON-unit |
|---|---|---|
| ENDFILE(file) | A READ or GET finds no more data | Raises ERROR |
| CONVERSION | Character data cannot be converted, for example letters into a number | Raises ERROR |
| ZERODIVIDE | Division by zero in fixed or floating arithmetic | Raises ERROR |
| SIZE | A value is too big for its target; disabled unless you enable it | Raises ERROR when enabled |
| SUBSCRIPTRANGE | A subscript is outside the array bounds; disabled unless enabled | Raises ERROR when enabled |
| ERROR | Any serious error, including the defaults above | Message, then the program ends |
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;ONSOURCE()returns the string that failed conversion andONCODE()returns a number identifying the condition. Look up ONCODE values in the PL/I documentation for your compiler level.ON ERROR SYSTEM;inside the ERROR ON-unit stops a second error from looping back into the same handler.PLIDUMPwrites a diagnostic dump; the option string controls its contents.- Some conditions are enabled with a prefix, for example
(SUBSCRIPTRANGE):in front of a procedure, often used in test.
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.
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
- IBM supplies cataloged procedures for compile, compile-and-bind and compile-bind-and-go; most sites wrap them in their own procs or build tools.
- By default the compiler reads source from column 2 to column 72 (the MARGINS option), so code starting in column 1 is ignored.
- Runtime output from PUT goes to SYSPRINT, and LE messages and dumps appear in the job output just as for COBOL.
- The compile listing, with its attribute and cross-reference tables, is your map when debugging an abend offset.
PL/I for COBOL maintainers
| COBOL | PL/I |
|---|---|
| Divisions, WORKING-STORAGE | DECLAREs inside each block |
| PERFORM UNTIL | DO WHILE / DO UNTIL |
| EVALUATE | SELECT / WHEN / OTHERWISE |
| FILE STATUS checks | ON-units such as ENDFILE, KEY, UNDEFINEDFILE |
| OCCURS | Array bounds after the name |
| CALL ... USING | CALL name(arguments) |
Common mistakes
An ON-unit that skips bad data without counting or reporting it hides real problems. Log, count and set a return code.
Without one, reaching end of file raises ERROR and the program ends abnormally. Establish ON ENDFILE before the first READ.
With the default margins, column 1 is not read as source. Indent code by at least one column.
What you will see at work
- Incident tickets for PL/I batch often start with an ONCODE in the job output; looking it up tells you which condition was raised.
- Reviews of PL/I code check that ON ERROR units report and stop cleanly rather than loop or hide failures.
- Teams that run both languages share the same JCL patterns, LE options and dump-reading skills across COBOL and PL/I.
Key terms
Check your understanding.
Take this lesson's quiz and save your progress. Free.