Let's understand Mainframe
Home Tutorials Interview Q&A Quiz Mainframe Memes Contact us About us

Module 5: REXX EXECIO File I/O


REXX- EXECIO File I/O

A REXX exec becomes truly useful when it can read and write datasets. EXECIO is the TSO/E command that moves lines between a dataset and a REXX stem variable, and it is the standard way REXX programs do file I/O. This page covers allocating datasets, reading with DISKR, writing with DISKW, and finishes with a complete file-processing exec.

What EXECIO does

  • EXECIO is a TSO/E host command, so inside REXX you run it as a quoted string: "EXECIO * DISKR INDD (STEM emp. FINIS)".
  • DISKR reads lines from a dataset; DISKW writes lines to a dataset.
  • The ddname (INDD above) must be allocated - with the ALLOCATE command in TSO, or with a JCL DD in batch.
  • Data lands in a stem: stem.1, stem.2, ... and stem.0 holds the number of lines.
  • After every EXECIO, the special variable RC holds the return code: 0 means success, anything else means a problem. Always check it.

Allocating a dataset to a ddname

  • In a TSO session, allocate before the EXECIO and free afterwards:
/* REXX */ "ALLOC F(INDD) DA('MYID.EMP.DATA') SHR REUSE" IF RC \= 0 THEN DO SAY 'ALLOC failed, RC =' RC EXIT 8 END /* ... EXECIO work happens here ... */ "FREE F(INDD)"
  • DA('MYID.EMP.DATA') - quote the dataset name or TSO prefixes it with your userid.
  • SHR REUSE - share the dataset, and reuse the ddname if it is already allocated.
  • FREE releases the dataset so it can be edited or deleted afterwards.
  • In batch JCL you skip ALLOCATE entirely - the DD statements allocate the ddnames (see the JCL below).

Reading a dataset: DISKR

  • "EXECIO * DISKR INDD (STEM emp. FINIS)" reads the whole dataset: * means all lines.
  • STEM emp. collects the lines; emp.0 tells you how many were read.
  • FINIS closes the dataset when the read completes.
  • Replace * with a number to read a fixed count, and use (OPEN) / (FINIS) to process a huge dataset in chunks instead of loading it all at once.
/* REXX - read the whole file at once */ "EXECIO * DISKR INDD (STEM emp. FINIS)" IF RC \= 0 THEN DO SAY 'Read failed, RC =' RC EXIT 8 END SAY 'Records read:' emp.0 DO i = 1 TO emp.0 SAY i || ':' emp.i END
/* REXX - chunked read for very large files */ "EXECIO 0 DISKR INDD (OPEN)" DO FOREVER "EXECIO 1000 DISKR INDD (STEM chunk.)" IF chunk.0 = 0 THEN LEAVE DO i = 1 TO chunk.0 /* process chunk.i here */ END END "EXECIO 0 DISKR INDD (FINIS)"

Writing a dataset: DISKW

  • Build the output lines in a stem, set stem.0 to the line count, then write them:
/* REXX */ out.1 = 'First report line' out.2 = 'Second report line' out.0 = 2 "ALLOC F(OUTDD) DA('MYID.EMP.REPORT') SHR REUSE" "EXECIO" out.0 "DISKW OUTDD (STEM out. FINIS)" IF RC \= 0 THEN SAY 'Write failed, RC =' RC "FREE F(OUTDD)"
  • "EXECIO" out.0 "DISKW ..." - the line count comes from the REXX variable out.0.
  • FINIS on a DISKW flushes the last lines and closes the dataset - without it, trailing records can be lost.
  • To create a brand-new dataset from REXX, allocate it with space parameters, or simpler, define the output DD in JCL with DISP=(NEW,CATLG).

Complete example: employee salary report

Input dataset MYID.EMP.DATA holds fixed-format lines - id in columns 1-5, name in 6-25, salary in 26-33. The exec reads every record, totals the salaries, and writes a report. Batch JCL that runs it follows.

/* REXX - PAYRPT: read employees, write a totals report */ "ALLOC F(INDD) DA('MYID.EMP.DATA') SHR REUSE" "EXECIO * DISKR INDD (STEM emp. FINIS)" IF RC \= 0 THEN DO SAY 'Read failed, RC =' RC "FREE F(INDD)" EXIT 8 END total = 0 rep.1 = 'EMPLOYEE SALARY REPORT' rep.2 = '======================' n = 2 DO i = 1 TO emp.0 PARSE VAR emp.i 1 id 6 name 26 salary total = total + salary n = n + 1 rep.n = id STRIP(name) salary END n = n + 1 rep.n = '----------------------' n = n + 1 rep.n = 'Employees:' emp.0 ' Total salary:' total rep.0 = n "ALLOC F(OUTDD) DA('MYID.EMP.REPORT') SHR REUSE" "EXECIO" rep.0 "DISKW OUTDD (STEM rep. FINIS)" IF RC \= 0 THEN SAY 'Write failed, RC =' RC "FREE F(INDD) F(OUTDD)" SAY 'Report written:' rep.0 'lines.'
//PAYRPT JOB (ACCT),'REXX PAYRPT',CLASS=A,MSGCLASS=X //STEP1 EXEC PGM=IRXJCL,PARM='PAYRPT' //SYSEXEC DD DSN=MYID.REXX.EXEC,DISP=SHR //INDD DD DSN=MYID.EMP.DATA,DISP=SHR //OUTDD DD DSN=MYID.EMP.REPORT,DISP=OLD //SYSTSPRT DD SYSOUT=* //SYSTSIN DD DUMMY
  • In batch, INDD and OUTDD come from JCL DDs, so the exec needs no ALLOCATE - the same exec runs in TSO with ALLOCATE or in batch with DDs.
  • PARSE VAR emp.i 1 id 6 name 26 salary splits each fixed-format record by column position.
  • EXIT 8 on read failure sets a non-zero step return code so the job visibly fails.





© copyright mainframebug.com
Privacy Policy
MainframeBug Assistant