Introductory text
Standard REXX allows files to be accessed using the seven functions
charin, charout, chars, linein, lineout, lines, stream. This REXX
version has fourteen I/O functions in total; the others remain for
backward compatibility but may be removed in future because their
functionality is covered by the stream() function.
Each I/O function may accept a stream name as a parameter. Usually,
the stream name is the path name of a file which will be accessed -
though other meanings may be given to streams by the "open", "popen"
and "stream" functions.
Associated with each currently accessed stream is a read pointer and a
write pointer. Characters or lines can be read from the file at the
position indicated by the read pointer, or they may be written to the
file at the position indicated by the write pointer. In each case the
pointer is updated to indicate the new file position after the read or
write. The file pointers may be also moved explicitly by various
functions. Note that the read and write pointers will in general be
different, in contrast to the usual Unix file pointer.
Each file is opened by REXX when it is first accessed, and closed when
REXX exits. Therefore files need not be opened and closed explicitly,
though in this version functions are provided for that purpose. If
many files are to be accessed, it is advisable to close files which are
no longer needed because otherwise the Unix error "Too many open files"
may result.
Two kinds of stream exist: persistent and transient. A persistent
stream is one which refers to a regular file, whereas a transient
stream is any other kind. In particular, ttys and pipes are transient
streams. The main difference between the two is that the read and write
pointers of a permanent stream may be repositioned, whereas those of a
transient stream may not.
If a function encounters an I/O error and is unable to perform its
function, then it will raise the NOTREADY condition. This condition
will be ignored unless it is trapped by SIGNAL ON or CALL ON. However,
in all cases it is possible to examine the most recent I/O error using
the STREAM() function.
The three streams "stdin", "stdout" and "stderr" are already open when
REXX starts up. They may be used just as any other files, but they are
also accessed by instructions such as "say" and "pull", and by Unix
commands. Because of this, REXX/imc only guarantees to be well-behaved
if stdin is never written to, and stdout and stderr are never read from.
The standard I/O functions CHARIN, CHAROUT, CHARS, LINEIN, LINEOUT,
LINES and STREAM all accept the empty string as a stream name. This is
interpreted identically to the word "stdin", except in the cases of
CHAROUT and LINEOUT, in which it means "stdout". However, the empty
string may not be used in the STREAM function in conjunction with the
the stream commands open, fdopen, popen or flush.
The I/O functions, and their descriptions, follow. Note that no
"stream" or "file" name may contain a NUL character (i.e. "00"x).
CHARIN([stream] [,[position] [,count]])
If stream is supplied, it is read from, otherwise "stdin" is read. The
charin function attempts to read a character from the stream, and
returns the result. If count is supplied, then that many characters
are read and returned. The length of the result may be less than the
number of characters requested if an error occurs. If position is
supplied, then the read pointer is seeked to that position (with 1
being the first character of the stream) before reading. If count is
zero, then the seek is performed without reading any characters.
If count>0 and no characters are read then the NOTREADY condition will
be raised.
If an interruption (^C) occurs during the read, then characters already
read may be lost.
NOTE: In order to read single characters from the keyboard, it is
necessary to set the terminal into a suitable mode. For example
the Unix command "stty cbreak -echo" allows single characters
to be read without echoing. This should be reset with
"stty -cbreak echo" before the program exits.
CHAROUT([stream] [,[string] [,position] ]
If stream is supplied, it is written to, otherwise stdout is written to.
If the string is supplied, it is written to the stream, otherwise no
write is performed. If the position is supplied, the write pointer is
set to that position (with 1 being the first character) before the
write (if any).
If no string and no position are supplied, then all pending output to
the stream is flushed, and the write pointer is set to the end of the
stream.
The result will be the number of characters left unwritten, and if that
is non-zero then the NOTREADY condition will be raised.
FDOPEN(fd [,[mode] [,stream]])
This function is for accessing files which have already been opened by
another program and whose file descriptor numbers are known. It should
not be used for opening files to which REXX already has access.
If mode is supplied, its first character must be one of "r" or "w",
meaning that the descriptor is to be opened for reading or read-write
respectively. The default is "r". This mode should match the mode of
the already-open file descriptor.
If the stream argument is supplied, then the given fd will be opened and
given that name so that all future references to the fd will call it by
the given name. Otherwise, future references to the fd will be by its
number.
If a stream argument is supplied which names an open stream, that
will be closed first. Note that the new stream will be opened on a
different descriptor, so in particular this function should not be used
to redirect the standard input, output or error.
The result from fdopen will be the return code given by the fdopen
system call.
Example. If this program is called "foo.rexx":
/* write to file descriptor 3 */
call fdopen 3,"w"
call lineout 3,"This is a line of text"
then the Bourne Shell command "rexx foo 3>foobar" will write a line of
text to the file foobar.
This call is equivalent to STREAM(stream,'c','fdopen' [mode] [,fd]) and
may be deleted in future releases.
FILENO(stream)
The result of this function is the file desriptor number associated with
the named stream, or -1 if that could not be determined (for example, the
stream is not open). This function may be used to pass file descriptors
on to shell commands, for instance as in "cat <&7".
This call is equivalent to STREAM(stream,'c','fileno') and may be
deleted in future releases.
FTELL(stream)
The result of this function is the current file pointer associated with
the given stream (with 1 meaning the beginning), that can be used as a
position parameter to the charin or charout calls. If that could not
be determined (for example, the stream is a pipe or is not open) then -1
will be returned.
NOTE: This is the actual file pointer, not the read or write pointer as
stored by REXX (though the answer will probably equal one of those,
according as to whether the last operation on the stream was a read
or a write).
This call is equivalent to STREAM(stream,'c','ftell') and may be
deleted in future releases.
LINEIN([stream] [,[line] [,count]])
If stream is supplied, it is read from, otherwise "stdin" is read. The
linein function attempts to read a line from the stream, and returns the
result (with the terminating newline character removed). If count is
supplied, it must be zero or one. If zero, then no read is performed,
and if one, one line is read. If an error occurs and no characters have
been read, then an empty string is returned and the NOTREADY condition
is raised. If line is supplied, then the read pointer is seeked to
that line number (with 1 being the first line of the stream) before
reading. If count is zero, then the seek is performed without reading
any characters.
If an interruption (^C) occurs during the read, then characters already
read may be lost.
NOTE: Seeking by line number is very inefficient, because every
character of the stream before that line has to be read (unless the
current read pointer is at a known line number less than that
requested, in which case only every character between the current
read position and the required position need be read).
LINEOUT([stream] [,[string] [,line]])
If stream is supplied, it is written to, otherwise stdout is written to.
If the string is supplied, it is written to the stream and terminated
with a newline character, otherwise no write is performed. If line is
supplied, the write pointer is set to that line number (with 1 being the
first line) before the write (if any). The line must not contain any
newline characters, because these will act as line separators in the
stream. To write text containing newline characters, please use charout
instead.
If no string and no line number are supplied, then all pending output to
the stream is flushed, and the write pointer is set to the end of the
stream.
The result will be 1 if the line was not successfully written, in which
case the NOTREADY condition will be raised. Otherwise the result will
be zero.
NOTE: seeking by line number is very inefficient.
LINES([stream])
If the named stream, or "stdin" if no stream is named, is a persistent
stream (or the name of a regular file), then the number of lines
available for reading will be counted and returned. Note that this
implies reading every character remaining in the file, and this should
be avoided if possible.
If the stream is a transient stream, then the result will be "1" if
characters may be read immediately from the stream, and "0" otherwise.
It is impossible to calculate the exact number of lines in this case.
If the stream is not already open and does not name a file which can be
read, then zero will be returned and the NOTREADY condition raised.
OPEN(file [,[mode] [,stream]])
The file specified is opened, if possible, and the error code from the
system call is returned. If mode is omitted, then the file is opened
for reading only, otherwise the first character of the mode must be
"r" (to open for reading), "w" (to open for read/write, with the file
being created or truncated initially), or "a" (to append, i.e. open for
read/write with the write pointer at the end of any existing data in the
file initially).
This function will not raise the NOTREADY condition, nor will it record
any error for STREAM() - the stream will remain unopened (or "UNKNOWN")
if the open fails. The return code from the call should be checked to
see whether an error occurred.
If the stream argument is supplied, then any future reference to the
open file will use this as the stream name - otherwise the filename
(exactly as specified in the open function call) will be used.
If a stream argument is supplied which already refers to an open file,
then that will be closed and the new file will be opened on the same
descriptor. The standard input, output or error may be redirected by
calling open with 'stdin', 'stdout' or 'stderr' as the stream argument.
This call is equivalent to STREAM(stream,'c','open' [mode][,file]) and
may be deleted in future releases.
POPEN(command [,[mode] [,stream]])
A Bourne Shell is started off in the background to run the given command
with a one-way pipe leading from or to it. If the mode is omitted, or
starts with the letter R, then the output of the command may be read
from the pipe. If a mode starting with the letter W is given, then the
input of the command may be written down the pipe.
NOTE: Care must be taken when opening pipes for writing, because if the
command fails or terminates unexpectedly then the Rexx program
will receive a SIGPIPE and terminate. To counter this see OPTIONS
'SIGPIPE' and always check for the NOTREADY condition when writing
down the pipe.
The return value from popen will be zero if the pipe was opened
successfully, or an error number if not. Note that the pipe may still
be opened successfully even if the command can not be executed: it
is the Bourne Shell's job to report that the command can not be executed.
The return code from the shell can be obtained with the pclose function.
This function will not raise the NOTREADY condition, nor will it record
any error for STREAM().
If the stream argument is supplied, then any future reference to the pipe
will use this as the stream name - otherwise the command in full will be
used.
If a stream argument is supplied which already refers to an open
stream, then that will be closed after the pipe has been successfully
opened. This means that the pipe will be opened on a different
descriptor, and the popen function should not be used to redirect the
standard input, output or error.
The pipe should be closed with the pclose function so that the shell
process may be removed from the process table. If that is not done,
then defunct processes will remain until REXX exits. This may be
acceptable for a small number of popen calls, but not if the REXX
program calls popen many times or is long-lived.
Example: the following program outputs in hex, using an "od" process:
output= "/bin/od -x"
call popen output,"w"
call lineout output,"This is some sample output"
call pclose output
This call is equivalent to STREAM(stream,'c','popen' [mode][,command])
and may be deleted in future releases.
STREAM(stream[,[option][,command]])
This function provides miscellaneous operations on the named stream.
The first character of the option must be "C", "D" or "S" (in upper or
lower case), if the option is given. If the option is omitted, then
"S" is assumed. The command parameter must be given if and only if the
option is "C".
Option "S"
The function returns the status of the stream as one of the following
strings:
"READY" - the stream is ready for input or output.
"NOTREADY" - the stream is not ready; usually this indicates that the
end of the file was reached.
"ERROR" - an I/O error has occurred.
"UNKNOWN" - the stream has not been accessed.
Option "D"
The function returns a description of the stream's status. This will
be "Ready", "Unknown", or the text of an error which has occurred.
This option may be used after a NOTREADY condition is trapped, to find
out what happened to the stream.
Option "C"
The function executes the given command on the stream and returns a
result depending on the command.
Valid commands in REXX/imc follow. All command names and mode
parameters may be given in mixed case, and wherever a comma appears in
the command, a space is acceptable as long as the parameter before it
is not omitted. For example, stream('file','c','Open R /tmp/testfile')
is a valid call to this function.
close - the named stream is closed and the return value from the
system call is returned. See CLOSE() for details.
fdopen [mode][,number] - if the number is given, it is used as a
numeric file descriptor and opened on the given stream.
Otherwise, the given stream is taken to be a numeric file
descriptor and opened. If the mode is omitted, "r" is
assumed. The return value from the system call is
returned. See FDOPEN() for details.
fileno - the file descriptor corresponding to the given stream is
returned. See FILENO() for details.
flush - the named stream is flushed. This is similar to calling
charout(stream). The return value is zero on success and
-1 on error, which may result if the stream is not open or
if a write error occurs on the stream. If a write error
occurs then the NOTREADY condition will be raised.
ftell - the file pointer of the given stream is returned. See
FTELL() for details.
open [mode][,file] - if the file name is supplied, it is opened on
the given stream. Otherwise, the given stream is taken
to be a file name and opened. If the mode is omitted,
"read" is assumed. The return value from the system call
is returned. See OPEN() for details. In addition, the
following options are supported for compatibility with
OS/2 Object Rexx and Regina, but note that the command
"OPEN WRITE" is incompatible because it truncates the file
whereas on OS/2 it appends to the file. Also note that
opening a stream for writing currently also implies opening
it for reading.
open write append - open the stream for appending.
open write replace - truncate and open the stream for writing.
open both - open the stream for reading and appending.
open both append - same as "open both".
open both replace - truncate and open the stream for reading and
writing.
pclose - the stream, which must have been opened by "popen", is
closed. The return value from the system call is
returned. See PCLOSE() for details.
persistent - the stream will be treated as a persistent stream.
Changing this attribute is not generally a good idea but it
might be useful if, for example, you open the floppy disk
device and want to seek to a particular block. Normally
the device would be considered a transient stream and
seeking would not be allowed on it.
popen [mode][,command] - if the command is supplied, a Bourne shell is
started up to execute it. Otherwise, the given stream
name is assumed to be a command and the shell is started
up to execute that. A pipe is opened from the shell to
the given stream. If the mode is omitted, "r" is
assumed. The return value from the system call is
returned. See POPEN() for details.
query <info> - the requested information is returned as detailed below.
The return value will be the empty string unless the first
argument of the STREAM function names either an open stream
or an existing file on the system. The <info> is one of
the following words.
datetime - returns the last modification time of the file in the
format mm-dd-yy hh:mm:ss. This function is deprecated in
favour of "timestamp" since it only returns a two-digit
year.
exists - returns a canonical name for the file (or, as detailed
above, an empty string if the file does not exist). If the
stream refers to a file whose full path name can be found,
the return value will be this name. Otherwise the return
value will be either a partial path name for the file, if
one is known, or the same as the stream name.
handle - returns the file descriptor corresponding to the stream
if it is currently open, otherwise an empty string (very
similar to the "fileno" stream command).
size - returns the size of the file in bytes, if it is a regular
file. Zero is returned if the file exists but is not a
regular file.
streamtype - returns "UNKNOWN" if the stream is not currently open,
otherwise "PERSISTENT" or "TRANSIENT" as appropriate to the
type of stream.
timestamp - returns the last modification time of the file in the
format yyyy-mm-dd hh:mm:ss.
transient - the stream will be treated as a transient stream (see the
"persistent" command).