Anda di halaman 1dari 13

File processing

NOTES & Illustrations on EXECIO:

NOTES:

EXECIO:

SYNTAX: EXECIO lines


DISKW ddname write parms
DISKR ddname read parms
DISKRU linenum read parms

WRITE Parms:
STEM varname OPEN|FINISH

READ Parms:
(FIFO | OPEN FINISH SKIP )
LIFO |
STEM Varname

This command controls I/O of information to and from a


dataset. Information can be read from a dataset to a data
stack for serialized processing or to a list of variables
for random processing. Information from the data stack or a
list of variables can be written to a data set.

You can use the EXECIO command to do various types of


I/O tasks, such as copy information to and from a data
set to add, delete, or update the information.

Restriction: The EXECIO command does not support I/O on


files allocated to data sets with spanned, track overflow,
or undefined record formats.

An I/O data set must be either sequential or a single


member of a PDS. Before the EXECIO command can perform
I/O to or from the data set, the data set must be
allocated to a file that is specified on the EXECIO
command. The EXECIO command does not perform the
allocation.

When performing I/O with a system data set that is


available to multiple users, allocate the data set as OLD,
before issuing the EXECIO command, to have exclusive use
of the data set.

When you use EXECIO, you must ensure that you use
quotation marks around any operands, such as DISKW, STEM,
FINIS, or LIFO. Using quotation marks prevents the
possibility of the operands being substituted as
variables.

For example, if you assign the variable stem to a value in


the exec and then issue EXECIO with the STEM option, if
STEM is not enclosed in quotation marks, it will be
substituted with its assigned value.

Lines:
The number of lines to be processed. This operand can be
a specific decimal number or an arbitrary number
indicated by *. When the operand is * and EXECIO is
reading from a data set, input is read until EXECIO
reaches the end of the data set.

If you specify a value of zero (0), no I/O operations are


performed unless you also specify either OPEN, FINIS, or
both OPEN and FINIS.

• If you specify OPEN and the data set is closed,


EXECIO opens the data set but does not read any
lines. If you specify OPEN and the data set is open,
EXECIO does not read any lines.

In either case, if you also specify a non-zero value


for the linenum operand, EXECIO sets the current
record number to the record number indicated by the
linenum operand.

• If you specify FINIS and the data set is open,


EXECIO does not read any lines, but EXECIO closes
the data set. If you specify FINIS and the data set
is not already opened, EXECIO does not open the data
set and then close it.
• If you specify both OPEN and FINIS, EXECIO processes
the OPEN first as described above. EXECIO then
processes the FINIS as described above.

DISKR

Opens a data set for input (if it is not already open)


and reads the specified number of lines from the data
set and places them on the data stack. If the STEM
operand is specified, the lines are placed in a list of
variables instead of on the data stack.

While a data set is open for input, you cannot write


information back to the same data set.

DISKRU

Opens a data set for update (if it is not already open)


and reads the specified number of lines from the data
set and places them on the data stack. If the STEM
operand is specified, the lines are placed in a list of
variables instead of on the data stack.

While a data set is open for update, the last record


read can be changed and then written back to the data
set with a corresponding EXECIO DISKW command.Typically,
you open a data set for update when you want to modify
information in the data set.

ddname

The name of the file to which the sequential data set or


member of the PDS was allocated. You must allocate the
file before you can issue EXECIO. For example, you can
allocate a file using the ALLOCATE command in the TSO/E
address space only or a JCL DD statement.

linenum

The line number in the data set at which EXECIO is to


begin reading. When a data set is closed and reopened as
a result of specifying a record number earlier than the
current record number, the file is open for:

- input if DISKR is specified


- update if DISKRU is specified
When a data set is open for input or update, the current
record number is the number of the next record to be
read. When linenum specifies a record number earlier
than the current record number in an open data set, the
data set must be closed and reopened to reposition the
current record number at linenum. When this situation
occurs and the data set was not opened at the same task
level as that of the executing exec, attempting to close
the data set at a different task level results in an
EXECIO error. The linenum operand must not be used in
this case.

FINIS:

Close the data set after the EXECIO command completes. A


data set can be closed only if it was opened at the same
task level as the exec issuing the EXECIO command.

You can use FINIS with a lines value of 0 to have EXECIO


close an open data set without first reading a record.

Because the EXEC command (when issued from TSO/E READY


mode) is attached by the TSO/E terminal monitor program
(TMP), data sets opened by a REXX exec are typically
closed automatically when the top level exec ends. Good
programming practice, however, would be to explicitly
close all data sets when finished with them.

OPEN:

Opens the specified data set if it is not already open.


You can use OPEN with a lines value of 0 to have EXECIO
do one of the following:

Open a data set without reading any records

Set the current record number (that is, the number of


the next record EXECIO will read) to the record number
indicated by the linenum operand, if you specify a
value for linenum.

STEM var-name
The stem of the set of variables into which information
is to be placed. To place information in compound
variables, which allow for easy indexing, the var-name
should end with a period. For example,
MYVAR.

When var-name does not end with a period, the variable


names are appended with numbers and can be accessed in a
loop such as:

"EXECIO * DISKR MYINDD (FINIS STEM MYVAR"


DO i = 1 to MYVAR0
this_line = VALUE('MYVAR'¦¦i)
END

In the first example above, the list of compound variables


has the stem MYVAR. and lines of information (records)
from the data set are placed in variables MYVAR.1,
MYVAR.2, MYVAR.3, and so forth.The number of variables in
the list is placed in MYVAR.0.

Thus if 10 lines of information were read into the MYVAR


variables, MYVAR.0 contains the number 10, indicating that
10 records are read. Furthermore, MYVAR.1 contains record
1, MYVAR.2 contains record 2, and so forth up to MYVAR.10
which contains record 10. All stem variables beyond
MYVAR.10 (i.e. MYVAR.11, MYVAR.12, etc.) are residual and
contain the values that they held prior to entering the
EXECIO command.

To avoid confusion as to whether a residual stem variable


value is meaningful, you may want to clear the entire stem
variable prior to entering the EXECIO command. To clear
all compound variables whose names begin with that stem,
you can either:

- Use the DROP instruction as follows, to set all


possible compound variables whose names begin with
that stem to their uninitialized values:

DROP MYVAR.

- Set all possible compound variables whose names begin


with that stem to nulls as follows:

MYVAR. = ''
LIFO
Places information on the data stack in LIFO (last in
first out) order.

FIFO
Places information on the data stack in FIFO (first in
first out) order. FIFO is the default when neither
LIFO or FIFO is specified.

SKIP
Reads the specified number of lines but does not place
them on the data stack or in variables. When the number
of lines is *, EXECIO skips to the end of the data set.

ILLUSTRATIONS:

1)This is an illustration of 2 execs to show how a data


set remains open. The first (top level) exec, EXEC1,
allocates a file and then calls EXEC2. The second exec
(EXEC2) opens the file, reads the first three records,
and then returns control to EXEC1. Note that EXEC2 does
not specify FINIS on the EXECIO command, so the file
remains open.

When the first exec EXEC1 regains control, it issues


EXECIO and gets the fourth record because the file is
still open. If EXEC2 had specified FINIS on the EXECIO
command, EXEC1 would have read the first record. In the
example, both execs run at the same task level.

FIRST EXEC ---- EXEC1


/*REXX exec (EXEC1) invokes another exec (EXEC2) to open/*
/* a file. EXEC1 then continues reading the same file. */

say 'Executing the first exec EXEC1'

"ALLOC FI(INPUTDD) DA(MYINPUT) SHR REUSE" /* Allocate input file */


/* */
/* Now invoke the second exec (EXEC2) to open the INPUTDD file. */
/* The exec uses a call to invoke the second exec. You can */
/* also use the TSO/E EXEC command, which would have the */
/* same result. */
/* If EXEC2 opens a file and does not close the file before */
/* returning control to EXEC1, the file remains open when */
/* control is returned to EXEC1. */
/* */
say 'Invoking the second exec EXEC2'
call exec2 /* Call EXEC2 to open file */
say 'Now back from the second exec EXEC2. Issue another EXECIO.'
"EXECIO 1 DISKR INPUTDD (STEM X." /* EXECIO reads record 4 */
say x.1
say 'Now close the file'
"EXECIO 0 DISKR INPUTDD (FINIS" /* Close file so it can be freed */
"FREE FI(INPUTDD)"
EXIT 0
SECOND EXEC ---- EXEC2
/* REXX exec (EXEC2) opens the file INPUTDD, reads 3 records, and */
/* then returns to the invoking exec (EXEC1). The exec (EXEC2) */
/* returns control to EXEC1 without closing the INPUTDD file. */
/* */
say "Now in the second exec EXEC2"
DO I = 1 to 3 /* Read & display first 3 records*/
"EXECIO 1 DISKR INPUTDD (STEM Y."
say y.1
END

2) This example copies an entire existing sequential data


set named prefix.MY.INPUT into a member of an existing
PDS named DEPT5.MEMO(MAR22), and uses the ddnames DATAIN
and DATAOUT respectively.

"ALLOC DA(MY.INPUT) F(DATAIN) SHR REUSE"


"ALLOC DA('DEPT5.MEMO(MAR22)') F(DATAOUT) OLD"
"NEWSTACK" /* Create a new data stack for input only */
"EXECIO * DISKR DATAIN (FINIS"
QUEUE '' /* Add a null line to indicate the end of information */
"EXECIO * DISKW DATAOUT (FINIS"
"DELSTACK" /* Delete the new data stack */
"FREE F(DATAIN DATAOUT)"

3) This example copies an arbitrary number of lines from


existing sequential data set prefix.TOTAL.DATA into a
list of compound variables with the stem DATA., and uses
the ddname INPUTDD:
ARG lines
"ALLOC DA(TOTAL.DATA) F(INPUTDD) SHR REUSE"
"EXECIO" lines "DISKR INPUTDD (STEM DATA."
SAY data.0 'records were read.'

4) To update the second line in data set EPT5.EMPLOYEE.LIST


in file UPDATEDD, allocate the data set as OLD to
guarantee exclusive update.
"ALLOC DA('DEPT5.EMPLOYEE.LIST') F(UPDATEDD) OLD"
"EXECIO 1 DISKRU UPDATEDD 2"
PULL line
PUSH 'Crandall, Amy AMY 5500'
"EXECIO 1 DISKW UPDATEDD (FINIS"
"FREE F(UPDATEDD)"

5) The following example scans each line of a data set whose


name and size is specified by the user. The user is given
the option of changing each line as it appears. If there
is no change to the line, the user presses the Enter key
to indicate that there is no change. If there is a change
to the line, the user types the entire line with the
change and the new line is returned to the data set.

PARSE ARG name numlines /* Get data set name and size from user */
"ALLOC DA("name") F(UPDATEDD) OLD"
eof = 'NO' /* Initialize end-of-file flag */
DO i = 1 to numlines WHILE eof = no
"EXECIO 1 DISKRU UPDATEDD " /* Queue the next line on the stack */
IF RC = 2 THEN /* Return code indicates end-of-file */
eof = 'YES'
ELSE
DO
PARSE PULL line
SAY 'Please make changes to the following line.'
SAY 'If you have no changes, press ENTER.'
SAY line
PARSE PULL newline
IF newline = '' THEN NOP
ELSE
DO
PUSH newline
"EXECIO 1 DISKW UPDATEDD"
END
END
END
"EXECIO 0 DISKW UPDATEDD (FINIS"

6) This example reads from the data set allocated to INDD to


find the first occurrence of the string "Jones". Upper
and lowercase distinctions are ignored. The example
demonstrates how to read and search one record at a time.
For better performance, you can read all records to the
data stack or to a list of variables, search them, and
then return the updated records.
done = 'no'
DO WHILE done = 'no'
"EXECIO 1 DISKR INDD"
IF RC = 0 THEN /* Record was read */
DO
PULL record
lineno = lineno + 1 /* Count the record */
IF INDEX(record,'JONES') ¬= 0 THEN
DO
SAY 'Found in record' lineno
done = 'yes'
SAY 'Record = ' record
END
ELSE NOP
END
ELSE
done = 'yes'
END
"EXECIO 0 DISKR INDD (FINIS"
EXIT 0

7) This exec copies records from data set prefix.MY.INPUT


to the end of data set prefix.MY.OUTPUT. Neither data
set has been allocated to a ddname. It assumes that the
input data set has no null lines.
"ALLOC DA(MY.INPUT) F(INDD) SHR REUSE"
"ALLOC DA(MY.OUTPUT) F(OUTDD) MOD REUSE"
SAY 'Copying ...'
"EXECIO * DISKR INDD (FINIS"
QUEUE '' /* Insert a null line at the end to indicate end of file */
"EXECIO * DISKW OUTDD (FINIS"
SAY 'Copy complete.'
"FREE F(INDD OUTDD)"
EXIT 0

8) This exec reads five records from the data set


allocated to MYINDD starting with the third record. It
strips trailing blanks from the records, and then
writes any record that is longer than 20 characters.
The file is not closed when the exec is finished.
"EXECIO 5 DISKR MYINDD 3"
DO i = 1 to 5
PARSE PULL line
stripline = STRIP(line,t)
len = LENGTH(stripline)
IF len > 20 THEN
SAY 'Line' stripline 'is long.'
ELSE NOP
END
/* The file is still open for processing */
EXIT 0

9) This exec reads the first 100 records (or until EOF) of
the data set allocated to INVNTORY. Records are placed
on the data stack in LIFO order. A message is issued
that gives the result of the EXECIO operation.
eofflag = 2 /* Return code to indicate end of file */
"EXECIO 100 DISKR INVNTORY (LIFO"
return_code = RC
IF return_code = eofflag THEN
SAY 'Premature end of file.'
ELSE
SAY '100 Records read.'
EXIT return_code

10) This exec erases any existing data from the data set
FRED.WORKSET.FILE by opening the data set and then
closing it without writing any records. By doing this,
EXECIO just writes an end-of-file marker, which erases
any existing records in the data set.

In this example, the data set from which you are


erasing records must not be allocated with a
disposition of MOD. If you allocate the data set with a
disposition of MOD, the EXECIO OPEN followed by the
EXECIO FINIS results in EXECIO just rewriting the
existing end-of-file marker.

"ALLOCATE DA('FRED.WORKSET.FILE') F(OUTDD) OLD REUSE"


"EXECIO 0 DISKW OUTDD (OPEN" /* Open the OUTDD file for writing,
but do not write a record */
"EXECIO 0 DISKW OUTDD (FINIS" /* Close the OUTDD file. This
basically completes the erasing
of any existing records from the
OUTDD file. */

Note that in this example, the EXECIO ... (OPEN command followed by
the EXECIO ... (FINIS command is equivalent to:

"EXECIO 0 DISKW OUTDD (OPEN FINIS"

11) This exec opens the data set MY.INVNTORY without


reading any records. The exec then uses a main loop to
read records from the data set and process the records.
"ALLOCATE DA('MY.INVNTORY') F(INDD) SHR REUSE"
"ALLOCATE DA('MY.AVAIL.FILE') F(OUTDD) OLD REUSE"
"EXECIO 0 DISKR INDD (OPEN" /* Open INDD file for input, but
do not read any records */
eof = 'NO' /* Initialize end-of-file flag */
avail_count = 0 /* Initialize counter */
DO WHILE eof = 'NO' /* Loop until the EOF of input
file */
"EXECIO 1 DISKR INDD (STEM LINE." /* Read a line */
IF RC = 2 THEN /* If end of file is reached,*/
eof = 'YES' /* set the end-of-file (eof)
flag */
ELSE /* Otherwise,a record is read*/
DO
IF INDEX(line.1,'AVAILABLE') THEN /* Look for records
marked "available"*/
DO /* "Available" record found */
"EXECIO 1 DISKW OUTDD" /* Write record to available
file */
avail_count = avail_count + 1 /* Increment "available"
counter */
END
END
END
"EXECIO 0 DISKR INDD (FINIS" /* Close INDD file that is currently
open */
"EXECIO 0 DISKW OUTDD (FINIS" /* Close OUTDD file if file is cur-
rently open. If the OUTDD file
is not open, the EXECIO command
has no effect. */
EXIT 0

12) This exec opens the data set MY.WRKFILE and sets the
current record number to record 8 so that the next
EXECIO DISKR command begins reading at the eighth
record.

"ALLOC DA('MY.WRKFILE') F(INDD) SHR REUSE"


"EXECIO 0 DISKR INDD 8 (OPEN" /* Open INDD file for input and set
current record number to 8. */
CALL READ_NEXT_RECORD /* Call subroutine to read record
on to the data stack. The next
record EXECIO reads is record 8
because the previous EXEC IO set
the current record number to 8.*/
.
.
.
"EXECIO 0 DISKR INDD (FINIS" /* Close the INDD file. */

ILLUSTRATION of the effect of residual data in STEM


variables:
13) This exec uses EXECIO to successively append the
records from 'sample1.data' and then from
'sample2.data' to the end of the data set
'all.sample.data'. It illustrates the effect of
residual data in STEM variables. Data set
'sample1.data' contains 20 records. Data set
'sample2.data' contains 10 records.

"ALLOC FI(MYINDD1) DA('SAMPLE1.DATA') SHR REUSE" /*input file 1 */


"ALLOC FI(MYINDD2) DA('SAMPLE2.DATA') SHR REUSE" /* input file 2 */
"ALLOC FI(MYOUTDD) DA('ALL.SAMPLE.DATA') MOD REUSE" /* output append
file */

/*******************************************************************/
/* Read all records from 'sample1.data' and append them to the */
/* end of 'all.sample.data'. */
/*******************************************************************/
exec_RC = 0 /* Initialize exec return code */
"EXECIO * DISKR MYINDD1 (STEM NEWVAR. FINIS" /* Read all records */
if rc = 0 then /* If read was successful */
do
/*****************************************************************/
/* At this point, newvar.0 should be 20, indicating 20 records */
/* have been read. Stem variables newvar.1, newvar.2, ... through*/
/* newvar.20 will contain the 20 records that were read. */
/*****************************************************************/
say "-----------------------------------------------------"
say newvar.0 "records have been read from 'sample1.data': "
say
do i = 1 to newvar.0 /* Loop through all records */
say newvar.i /* Display the ith record */
end
"EXECIO" newvar.0 "DISKW MYOUTDD (STEM NEWVAR." /* Write exactly
the number of records read */
if rc = 0 then /* If write was successful */
do
say
say newvar.0 "records were written to 'all.sample.data'"
end
else
do
exec_RC = RC /* Save exec return code */
say
say "Error during 1st EXECIO ... DISKW, return code is " RC
say
end
end
else
do
exec_RC = RC /* Save exec return code */
say
say "Error during 1st EXECIO ... DISKR, return code is " RC
say
end
If exec_RC = 0 then /* If no errors so far... continue */
do
/***************************************************************/
/* At this time, the stem variables newvar.0 through newvar.20 */
/* will contain residual data from the previous EXECIO. We */
/* issue the "DROP newvar." instruction to clear these residual*/
/* values from the stem. */
/***************************************************************/
DROP newvar. /* Set all stems variables to their */
uninitialized state */
/***************************************************************/
/***************************************************************/
/* Read all records from 'sample2.data' and append them to the */
/* end of 'all.sample.data'. */
/***************************************************************/
"EXECIO * DISKR MYINDD2 (STEM NEWVAR. FINIS" /*Read all records*/
if rc = 0 then /* If read was successful */
do
/*************************************************************/
/* At this point, newvar.0 should be 10, indicating 10 */
/* records have been read. Stem variables newvar.1, newvar.2,*/
/* ... through newvar.10 will contain the 10 records. If we */
/* had not cleared the stem newvar. with the previous DROP */
/* instruction, variables newvar.11 through newvar.20 would */
/* still contain records 11 through 20 from the first data */
/* set. However, we would know that these values were not */
/* read by the last EXECIO DISKR since the current newvar.0 */
/* variable indicates that only 10 records were read by */
/* that last EXECIO. */
/*************************************************************/

say
say
say "-----------------------------------------------------"
say newvar.0 "records have been read from 'sample2.data': "
say
do i = 1 to newvar.0 /* Loop through all records */
say newvar.i /* Display the ith record */
end
"EXECIO" newvar.0 "DISKW MYOUTDD (STEM NEWVAR." /* Write
exactly the number of records read */
if rc = 0 then /* If write was successful */
do
say
say newvar.0 "records were written to 'all.sample.data'"
end
else
do
exec_RC = RC /* Save exec return code */
say
say "Error during 2nd EXECIO ...DISKW, return code is " RC
say
end
end
else
do
exec_RC = RC /* Save exec return code */
say
say "Error during 2nd EXECIO ... DISKR, return code is " RC
say
end
end
"EXECIO 0 DISKW MYOUTDD (FINIS" /* Close output file */
"FREE FI(MYINDD1)"
"FREE FI(MYINDD2)"
"FREE FI(MYOUTDD)"
exit 0

Anda mungkin juga menyukai