The REXX Stream I/O functions are:
STREAM() | function to control or query stream I/O |
LINEIN() | function to read records |
LINEOUT() | function to write records |
CHARIN() | function to read characters |
CHAROUT() | function to write characters. |
These functions allow to read or write to CMS files, but also to/from:
As stream I/O functions are part of REXX SAA Level 2, they are also available on OS/2 and Object REXX, although the functionality and performance may be different. See Appendix F. "Host versus Personal Systems" for more details on these differences.
We reproduce the complete HELP of the STREAM() function here. It may seem important due to the number of pages, but we will see later that it is not so for CMS. For REXX on personal systems, it is an important function, and that's why we cover it in detail.
Format
>>--STREAM(name--+-----------------------------------+--)----->< ! +-State----------------------+ ! +-,--+----------------------------+-+ !-Command--,--stream_command-! +-Description----------------+
This function requests information on the state of an input or output stream or carries out some specific operation on the stream.
The first argument, name, specifies the stream to be accessed.
On CMS, the data streams that can be processed, and the syntax to name them, are:
Data stream | Stream naming | Description |
---|---|---|
Reader file | spid RDRFILE CMSOBJECTS. | where spid is the spool ID of the file. An asterisk in the spid field can be used to specify the first file in the reader. |
Punch file | VIRTUAL PUNCH CMSOBJECTS. | |
Printer file | VIRTUAL PRINTER CMSOBJECTS. | |
SFS file | filename filetype dirname | Asterisks may not be used anywhere in the file name or file type. |
Minidisk or accessed SFS directory files | filename filetype
or filename filetype filemode | For an input operation, if no file mode or a file mode of asterisk is supplied, the first instance of the file in the CMS search order will be used. For an output operation, filemode must be specified. Asterisks may not be used anywhere in the file name of file type. |
Program stack | PROGRAM STACK CMSOBJECTS. or PROGRAM STACK CMSOBJECTS.LIFO or PROGRAM STACK CMSOBJECTS.FIFO | (Also referred to as an "external data queue"). LIFO and FIFO may be appended, to designate LIFO or FIFO stacking on output. If neither is specified, FIFO is the default and will be appended to the name of the stream when it is returned by the STREAM and CONDITION functions. When reading from the stack, lines are always read from the top. If the program stack has been opened LIFO, it cannot be used FIFO, inless it is closed and reopened FIFO. Similarly, if the program stack has been opened FIFO, it cannot be used LIFO unless it is closed and reopened LIFO. |
Default stream | '' (null string) | For input, this reads from the terminal input buffer or from user input (VM READ) if the buffer is empty. For output, this displays on the user's console. The default stream is always open, therefore, you do not need to open it. |
The second argument describes the action to be carried out. (Only the capitalized letter is needed ; all characters following it are ignored). Actions can be:
llname llretcode llreascode(where llname is the lower level program name, llretcode is the lower level return code, and llreascode is the lower level reason code).
ERROR | The stream has been subject to an erroneous operation (possibly during input, output, or through the STREAM() function). You may be able to obtain additional information about the error by invoking the STREAM() function with a request for the description. |
NOTREADY | The stream is known to be in a state such that usual input or output operations attempted upon it would raise the NOTREADY condition. For example, a simple input stream may have a defined length; an attempt to read that stream (with the CHARIN() or LINEIN() built-in functions, perhaps) beyond that limit may make the stream unavailable until some operation resets the state of the stream. |
READY | The stream is known to be in a state such that usual input or output operations may be attempted (this is the usual state for a stream, though it does not guarantee that any particular operation will succeed). |
UNKNOWN | The state of the stream is unknown. That is, the stream is closed or has not yet been opened. |
The stream_commands:
The stream_command argument must be used when - and only when - you select the Command operation. The syntax is:
STREAM(name,'C',stream_command)
In this form, the STREAM() function itself returns a string corresponding to the given stream_command if the command is successful. If the command is unsuccessful, STREAM() returns an error message string. For most error conditions, additional information is returned is in the form of a return code and reason code.
See the VM/ESA: REXX/VM Reference for a full explanation of the return codes and reason codes generated by the CSL routines that perform the I/O. For the lower level routine codes not listed there, see the following books:
The argument stream_command can be any expression that REXX evaluates as one of the following command strings. (All capitalized letters are needed ; case is insignificant).
OPEN options
opens the named stream. The format of this command is:
>>----OPEN-----! Options !------------------------------------------->< Options: +-LRECL--nnnnn-+ +-RECFM-V-+ +-TEXT---+ +-LINEEND-15-+ !-+---------+-+--------------+-+---------+-+--------+--------------+-! !-READ----! +-LRECL--nnnnn-+ !-RECFM-F-! +-BINARY-+ +-LINEEND-xx-+ !-WRITE---! +-RECFM-V-+ !-NEW-----! +-REPLACE-+
The stream may be opened for reading or writing by specifying an intent. Valid values for intent are:
READ | Open for reading only, object must exist. |
WRITE | open for read/write, object will be created if it does not exist. |
NEW | open for read/write, object must not exist and will be created (VM/ESA Only). |
REPLACE | open for read/write, object will be created if it does not exist or will be replaced if it does exist. A replaced file is considered a new file, and, therefore, the record format and logical record length may change (VM/ESA Only). |
If an intent is not specified, then the open type will be determined by the capability of the named stream if known: READ for read-only streams and WRITE otherwise. If unknown, WRITE is used.
Next options apply to VM/ESA only:
LRECL nnnnn | used to specify the logical record length of the stream. If this parameter is not specified, the logical record length of the stream is used, if known. Otherwise, 1024 is used. |
TEXT or BINARY | specifies if LINEEND characters are significant in character I/O operations. BINARY means that all character codes may be present in the data stream and no indication of LINEEND characters will be provided or searched for. TEXT means that LINEEND characters are not included in the data stream and line ends should be noted. That is, LINEEND characters are appended to the end of each line when passing data to the user on character input operations; data to be written to a stream on character output operations is split at LINEEND characters. These LINEEND characters are never written to the data stream. Line operations are not affected by this parameter. TEXT is the default. |
LINEEND xx | specifies the line end character to be used when doing character-based operations on TEXT streams (ignored for line-based operations). The xx can be one or two hexadecimal digits that define the character to be used as the line end indicator. A leading 0 will be supplied if only one digit is given. These must be valid hexadecimal digits and contain no blanks. If this parameter is not specified, 15 is used. For portability, it is recommended that a value of 3F or less be used. |
The STREAM() function itself returns the string READY: followed by a unique stream identifier if the named stream is successfully opened. This identifier, or file handle as it is also called, can be used in functions like LINEIN(). This unique identifier contains printable and not printable characters. If unsuccessful, the returned string consists of ERROR: followed by the return code and reason code from the open routine that failed, and then the words Open failed.
CLOSE
closes the named stream. The STREAM() function
itself returns READY: if the named stream is successfully closed. If the
close is unsuccessful, the returned string is ERROR: followed by the
return code and reason code from the failing routine and then Close
failed. For an SFS file, this causes a close with commit. If an attempt
is made to close an unopened stream, then STREAM() returns a null string.
LINEPOS offset type
is for VM/ESA only, and
sets the read or write line pointer to a
specified offset within a persistent stream.
Offset is a positive whole number that may have a modifier as
follows:
= or blank | specifies that offset is forward from the beginning of the stream. This is the default if no modifier is supplied. |
< | specifies that offset is backward from the end of the stream. |
+ | specifies that offset is forward from the current read/write position. |
- | specifies that offset is backward from the current read/write position. |
type | is either READ or WRITE, specifying that the read or write position is to be changed. |
In order to position the line write pointer to the position just past the end of a stream, use an offset of <0. In order to position the line write pointer to the last record of a stream, use an offset of <1.
In order to use this command, the named stream must first be opened (with the OPEN stream command described above or implicitly with an I/O function call).
The STREAM() function itself returns the new position in the stream if the read/write position is successfully located or an error message otherwise. This error message will include the string ERROR: followed by the return code and reason code from the failing routine, and then followed by the message, Point failed.
SEEK offset
is for OS/2 and Object REXX only, and sets the read or write
position a given number (offset) within a persistent stream. On Personal Systems
the read and write positions are the same. To use this command, the
named stream must be first opened with the OPEN stream command. The
offset number can be preceded by one of the following
characters:
= | explicitly specifies the offset from the beginning of the stream. This is the default if no prefix is supplied. |
< | specifies offset from the end of the stream |
+ | specifies offset forward from the current read or write position. |
- | specifies offset backward from the current read or write position. |
In addition, the STREAM() function returns specific information about a persistent stream when used with the following commands. Under certain error conditions, and when a stream does not exist, a null string is returned. (All capitalized letters are needed; case is insignificant).
QUERY DATETIME
returns the date and time stamps of a stream (date
and time when last modified). For example:
stream(spid 'RDRFILE CMSOBJECTS.','c','query datetime') (CMS) stream('..\file.txt','c','query datetime') (OS/2)
The date is returned in the form:
mm/dd/yyyy hh:mm:ss (CMS) mm-dd-yy hh:mm:ss (OS/2)
For a reader file (CMS only), this is the date and time the file was created (punched). If the file is not open, the year is 0000.
For an SFS file or minidisk file, this is the date and time the file was last modified.
For all other objects, zeros are returned to indicate that the date and time are undetermined.
QUERY EXISTS
returns the full name of the object if it exists, or
a null string otherwise. For example:
stream('YOURDATA FILE *','c','query exists') (CMS) stream('..\file.txt','c','query exists') (OS/2)
For SFS and minidisk files, this indicates whether the file exists. For a minidisk file or an accessed SFS directory, if the file mode number was omitted or the file mode was specified as an asterisk (*), then the full file name will be returned. For SFS, the fully qualified name is returned.
For a reader file, this indicates whether the file is present in the virtual reader. If an asterisk (*) was specified for the spool ID, then this will return the full name (spool_id RDRFILE CMSOBJECTS) of the first file in the reader if it exists.
QUERY SIZE
returns the size in lines (or records) of a stream on
VM/ESA. On Personal Systems, it returns the size in bytes of the
persistent stream.
For example:
stream(punch,'c','query size')
For minidisk and SFS files, this is the number of records in the file. For a reader file, this is the number of card images in the reader file. For a virtual punch or virtual printer, this is the number of records written to the device since it was opened if it is open and zero if it is closed.
For a file on Personal Systems, it is the number of bytes.
Next options are available for VM/ESA only:
QUERY FORMAT
returns the record format and logical record length
of a stream.
This information is returned in the form:
recfm lrecl
For a virtual unit record device, the device's characteristics are evaluated according to device type such as reader, printer, and punch.
QUERY INFO
returns the record format, logical record length,
number of records, date of last update, and time of last update.
The information is returned in the form:
recfm lrecl #records mm/dd/yyyy hh:mm:ss
Refer to the commands in this list for the various pieces (format, size, and datetime) for information on the content of the returned string.
QUERY LINEPOS READ
returns the value of the line read pointer
for a persistent stream (or 0 if the stream cannot be read or is not
open).
QUERY LINEPOS WRITE
returns the value of the line write pointer
for a persistent stream (or 0 if the stream cannot be written to or is
not open).
This function returns the number of completed lines remaining in the character input stream name. On Personal Systems, it only returns 1 if there are lines remaining between the current read position and the end of file, because these systems do not know about records.
|
You can have problems with this function. If your file is on a regular
minidisk (thus not SFS), then the LINES(fileid) function
returns the number of lines in the file, but subsequent non-streaming
commands (like FINIS, XEDIT, ERASE, COPYFILE, EXECIO or
RENAME)
may fail as the file is already opened by the LINES()
function.
Possible error messages you may get: DMSEIO632E I/O error in EXECIO; rc=70 from FSREAD command DMSERS1198E File MY FILE A is currently open; it must be closed before it can be erased DMSOPN1198E File MY FILE A1 is currently open; it must be closed before the operation can complete DMSRNM1198E File MY FILE A1 is currently open; it must be closed before the operation can complete Next is an example that will fail: /* LINES leaves the file open for read and write */ address command if lines('MY FILE A')>0 then 'COPYFILE MY FILE A = = B' exit If the procedure is executed, it will display: DMSOPN1198E File MY FILE A1 is currently open; it must be closed before the operation can complete A solution is to close the file again before to use the other functions, or not to use the LINES() function to test the number of records in a file. |
The CHARS() function returns either 0 or 1 depending on whether there are characters available in the input stream. CHARS() will return 1 if there is at least one character available in the stream and 0 otherwise. If you omit name or it is null (both signifying the default input stream), 1 is returned.
On Personal Systems, it will return the exact number of characters remaining in the input stream.
>>--LINEIN(--+------+--+-------------------------+--)------>< +-name-+ +-,--+------+--+--------+-+ +-line-+ +-,count-+
We already discussed this in previous lesson.
>>--CHARIN(--+------+--+---------------------------+--)------>< +-name-+ +-,--+-------+--+---------+-+ +-start-+ +-,length-+
returns a string of up to length single-byte characters read from the character input stream name. If you omit name, characters are read from the default input stream (STDIN on Personal Systems). The default length is 1.
For persistent(footnote) streams, a read position is maintained for each stream. On Personal Systems, this is the same as the write position. Any read from the stream starts at the current read position by default. When the language processor completes reading, the read position is increased by the number of characters read. A start value of 1 (the only valid value in CMS) may be given to specify the start of the stream. On Personal Systems, any start value is accepted and indicates an explicit read position.
If you specify a length of 0, then the read position is set to the value of start but no characters are read and the null string is returned.
Only on CMS, if the number of characters being returned causes a read of an entire line or multiple lines in the stream, a LINEEND character is appended at the end of each line. (See the STREAM() function for more information on the LINEEND character). This is only for files that were opened with the TEXT option on the STREAM() function. TEXT is the default if not specified on the STREAM()function or if the file is implicitly opened by the first I/O call. This LINEEND character is counted in the number of characters returned.
In a transient stream, if there are fewer than length characters available, then execution of the program generally stops until sufficient characters do become available. If, however, it is impossible for those characters to become available because of an error or other problem, the NOTREADY condition is raised and CHARIN() returns with fewer than the requested number of characters.
Here are some examples:
CHARIN(myfile,1,3) -> 'MFC' /* the first 3 */ /* characters */ CHARIN(myfile,1,0) -> '' /* now at start */ CHARIN(myfile) -> 'M' /* after last call */ CHARIN(myfile,,2) -> 'FC' /* after last call */ /* Reading from the default input (here, the keyboard) */ /* User types 'abcd efg' */ CHARIN() -> 'a' /* default is */ /* 1 character */ CHARIN(,,5) -> 'bcd e'
And an example valid for VM/ESA only:
/* assume TEXT and LINEEND='15'x, only 1 character, A, left on */ /* the line and the next line starts with B */ CHARIN(myfile,,3) -> 'A B' /* in hex: 'C115C2'x */
From the description we can again see the difference between the character oriented personal systems and the record oriented host system. See Appendix F. "Host versus Personal Systems" for other examples.
The LINEOUT() and CHAROUT() functions will be discussed in the chapter discussing file output (chapter 17). Chapter 16 will discuss file input techniques.
A persistent stream is for example a disk file. On the opposite, a
transient stream
is for example your screen input or output. Once you have written to
a transient stream, you don't have the possibility to read the
information back again. Similarly, when you read from a transient
stream, you normally can't read it again.
Back to text