REXX Function Package for OpenEdition MVS
This function package extends the REXX language on OS/390 when used in an OpenEdition MVS REXX environment. It includes functions for standard REXX I/O. A number of I/O stream commands are provided to help control stream processing. Additional functions are also included to easily access some common file services and environment variables.
Also included with this package is the ability to interrupt a running REXX program and enter an immediate REXX command such as TS to start interactive tracing.
The function BPXWUNIX is the only function in this package that can also be run outside of an OpenEdition REXX environment, like in TSO.
Please direct comments and additional requests to
Bill Schoen wjs@us.ibm.com
OpenEdition has a number of facilities for performing I/O. This includes ADDRESS MVS EXECIO and several commands using ADDRESS SYSCALL. This function package adds the seven REXX I/O functions. The STREAM() function is for status and control of I/O streams. The input functions are CHARIN() and LINEIN(). CHARS() and LINES() are used to determine if data remains in an input stream. The output functions are CHAROUT() and LINEOUT(). Streams can only be used on files in the OpenEdition file system hierarchy. Data sets can be accessed by making the data sets visible through the file hierarchy using NFS.
Streams can be opened implicitly or explicitly. A stream is implicitly opened by using a pathname as the stream name for one of the six input or output functions. If the function is CHAROUT or LINEOUT, the file is opened for output. If the file does not exist it is created. Permission bits for newly created files is 0666 applied to your process umask. The position for the first write is set to the end of file unless the function call explicitly specifies a write location. The file is opened for input if one of the four input functions is used. The stream open will fail if the file does not exist. For either input or output, if the pathname cannot be accessed, the stream open will fail.
A stream can be opened for both input and output when the stream is implicitly opened. The input and output locations are independent of each other. If the stream is opened for both input and output, two file descriptors are used. The STREAM CLOSE command will close the stream and, therefore, both file descriptors.
A message is written to stderr if the file cannot be opened. The I/O function returns as though the stream is empty, at end of file, and the file cannot be extended.
A stream can be explicitly opened using the STREAM() function. File streams are explicitly opened using the OPEN command. Process streams are only opened using the POPEN command. The advantages of explicitly opening file streams is that the program can determine that the stream open failed. The program can also have several separate streams for the same file.
When a stream is explicitly opened, the STREAM() function returns a string which is the name of the stream. This is the only name that can be used to identify the stream. Multiple opens for the same pathname will open multiple streams, each with its own name.
Process streams give you the capability to run a shell command and either provide its input or receive its output. To write the input for the command, use the POPEN WRITE command. To receive the command output, use the POPEN READ command. STREAM() will return a string which is the name of the process stream. Use this name on the input functions for POPEN READ or output functions for POPEN WRITE.
A process stream spawns /bin/sh -c your_command. The process inherits stderr and either stdin or stdout. If the process is opened for read, stdout for the process is a pipe, otherwise stdin is a pipe. The shell completion code is returned as the result for the STREAM PCLOSE command. PCLOSE wll close your end of the pipe and wait for the process to terminate.
These functions are fully enabled for large files (>2GB). HFS currently supports file offsets close to 2**43. All numbers that are input on the functions must be integers. The default precision for REXX is 9 digits. If arithmetic is used on large numbers, be sure to change your precision appropriately using the NUMERIC DIGITS statement.
A REXX program can be interrupted with the interrupt signal, usually control-c. In response to this interrupt, the REXX interrupt handler will suspend execution of the REXX program and prompt for an immediate command, selected by number. The following commands are supported:
The program can use the function rexxopt() to disable this capability or attach this signal handler to other signals.
REXX programs that are run as setuid or setgid programs cannot be interrupted to issue an immediate command.
BPXWUNIX(cmd[,stdin[,stdout[,stderr[,env]]]])
Run a shell command and optionally provide its stdin and trap its stdout and stderr, and export a set of environment variables. The shell is run passing a single command similar to sh -c cmd. This does not run a login shell.
This function can be used ouside of the UNIX REXX environment (e.g., in TSO).
When this function is used in such an environment, stdin, stdout, stderr, and environment variables will not be inherited from the current process environment.
Return Information:
If the stdout or stderr stems are specified, they will be filled as appropriate.
If the return value of the function is in the range 0-255, it is the exit status of the command. Negative return values indicate failure. This is generally a signal number. Numbers less than -1000 indicate a stop code.
Examples:
trap output from the ls command and display it: call bpxwunix 'ls -l',,out. do i=1 to out.0 say out.i end Send output from above to word count and print byte count: call bpxwunix 'wc',out.,bc. parse var bc.1 . . count say 'byte count is' count Trap output on stack and feed it to word count: if bpxwunix('ls -l',,stack)=0 then call bpxwunix 'wc',stack
CHARIN([name][,[start][,length]])
Returns a string of up to length characters read from the stream specified by name. The location for the next read is the current location increased by the number of characters returned. This service does no editing of the data.
Example:
say charin(file,,256) /* read next 256 characters */ call charin file,5*80+1,0 /* set read location to the 6th 80 byte record */
CHAROUT([name][,[string][,start]])
Returns the number of characters remaining after attempting to write string to the stream specified by name. The location for the next write is the current location increased by the number of characters returned. If string is omitted, no data is written and the write location is to the value start. If start is also omitted, the write position is set to the end of file.
Example:
call charout ,'hello world'esc_n /* write the string to stdout */ call charout file /* set write position to end */
CHARS([name])
Returns the number of characters remaining in the input stream specified by name. For persistent streams, it is the number of characters between the current read location and the end of the stream.
If the stream was created by the stream POPEN command, CHARS will return the number of bytes currently in the pipe, or, if no bytes are in the pipe and the process is still active, it will return 1.
Example:
remainder=chars() /* get number of bytes in the stdin stream */
CHMOD(pathname,[operation]mode)
returns 0 if the mode for the specified pathname is changed, otherwise the system call error number is returned.
Example:
call chmod file,660 /* set permissions for owner/group R/W */ call chmod file,+4 /* add read permission for other */
CONVD2E(timestamp)
Convert a timestamp to POSIX epoch time.
Returns the time in seconds past the POSIX epoch (1/1/1970). The argument is a 14 character string in the form mmddyyyyHHMMSS.
Example:
say convd2e('04211999071500') /* posix time for 4/21/99 7:15:00 */
DIRECTORY([newdirectory])
returns the current directory, first changing it to newdirectory if the argument is supplied and you have access to that directory.
Example:
call directory '/u/wjs' /* change current directory to /u/wjs */
ENVIRONMent(variable name[,new value]) ENVIRONMent(variable name[,,operation])
queries and alters environment variables. The stem __ENVIRONMENT. is not altered through this service. That stem contains the environment variables on entry to the REXX program and is available for your use. Alterations of the environment will be used on subsequent calls to the STREAM POPEN command and ADDRESS SH.
Example:
path=environment('PATH') /* get value of PATH env variable */ call environment 'PATH','.' /* reset PATH to current directory */ call environment 'PATH',,'d' /* delete PATH env variable */
EXISTS(file name)
returns the full pathname for the specified file. If the file does not exist the function returns a null string.
Example:
say exists('myfile') /* print the full path for the file myfile */
GETPASS(prompt)
Prints Example:
Returns no lines or 1 line from the specified string and sets the
location for the next read to the beginning of the next line.
The data is assumed to be text. The newline character is the line
delimiter and is not returned.
A null string is returned if no line is returned. Note that this
appears exactly the same as null line in the file. Use the CHARS or
LINES functions to determine if you are at end of file. The STREAM
function can be used to determine if there is an error condition on
the stream.
Example:
Returns 0 or 1 lines remaining to write after attempting to write
string to the stream specified by name. A newline character is written
following string. If an error occurs on the write, some data may be
written to the stream and the function will return the value 1.
Example:
returns a 1 if data remains in the stream otherwise 0. Programs
should check for a value of 0 or non-zero.
Example:
This function enables or disables the trapping of output from
commands run using ADDRESS TSO. It
returns the name of the variable in which trapped output is stored.
If trapping is off, the word OFF is returned.
The following arguments can be specified.
See the section on ADDRESS TSO for additional information.
Example:
Sets or resets one of the following options:
Example:
This name is an alias for BPXWUNIX. See BPXWUNIX for usage
information. This name is provided for compatibility reasons. The
preferred name is BPXWUNIX which will also work from TSO and some other
MVS REXX environments.
places the process in a signals enabled wait and returns after the
wait expires. If a signal interrupts the wait, the function returns the
number of seconds remaining for the wait, otherwise it returns 0.
Example:
returns the state of the stream or the result of the command.
Example:
Example:
Example:
Example:
Optional arguments may be specified with WRITE and optionally
followed by octal permission bits. WRITE will always open the file
with O_CREAT creating the file is it does not exist.
The additional arguments are:
Example:
Example:
Example:
Example:
The function returns a string which is the name to be used for the
stream on subsequent I/O functions. This string is the only name
by which this stream will be known.
Example:
Example:
Example:
Example:
Example:
Commands addressed to TSO will be run in a TSO TMP running in
a separate address space and process
from your REXX program. This provides the
capability to run TSO commands but does not provide the capability
to use TSO commands to affect your REXX environment or have REXX
statements or other host command environments affect your TSO process.
The TSO process is started when the first TSO command is run and
persists until your REXX program
terminates or you run the TSO LOGOFF command. This process can be
observed with a ps shell command as the program bpxwrtso. Unexpected
termination of this process will cause the next TSO command to fail
with return code 16. A subsequent command will start a new TSO process.
command may be any TSO command, clist, or REXX exec that can run
in a batch TSO TMP.
Most native TSO commands use TGET for input. This will result in a
command error and the command will generally terminate. This
includes commands that prompt for missing arguments.
For commands
that are able to read input, the source of the input will
first be any data currently on your stack followed by any data in
your REXX program's standard input stream. Regardless of whether
the command processes input, all data on the stack will be queued
to the TSO command. The stack will be empty after running any TSO
command. The standard input stream may also be queued as input to
the TSO command. For example, if you have a file redirected as
input and you run a TSO command prior to processing that file, some
or all of the file may be queued to the TSO command. If input is the
terminal, queued input may be queued to the TSO command. This
characteristic can be used to interact with some TSO commands.
By default, all command output is directed to your REXX process's
standard output stream. The outtrap() function can be used to trap
command output in variables.
The special REXX variable RC will usually
contain the return code from the TSO command.
If the command abends, is not found, or other error is detected,
special return codes will be set and it is possible that a descriptive
message will be written to the standard error stream.
-3 generally means the TSO command was not found.
16 generally means a processing error was encountered.
Other negative numbers generally are abend codes. These should
be accompanied by a message containing an abend reason code.
Simple command
Trap command output and print
Run a REXX exec in TSO
Functional replacement for the tsocmd utility
ADDRESS TSO is still under development and may have some problems.
It should not introduce any integrity problems, but it is possible
for this service to loop, hang, or abnormally terminate.
No specific problems are known at this time. If you should encounter
any problems or quirks, please email any information you have regarding
the problem to Bill Schoen at wjs@us.ibm.com.
This function package is packaged in an unloaded load library.
Use the TSO
RECEIVE command with option INDA() to restore it. The name of this
file on this server is rexxfunc.unload and must be transfered in binary
format and restored to an MVS system as an FB 80 data set.
Once on an MVS system, use tso receive inda(rexxfunc.unload)
to restore the data set. Unless you direct it elsewhere, it will
restore in data set prefix.REXXFUNC.LOADLIB.
This load library contains several load modules.
The function package itself is BPXWRXFP with an alias BPXWRXSA.
Other modules are replacements for modules distributed with OS390.
BPXWRXFP and alias must be in the LINKLIST or in your STEPLIB.
BPXWRTCM must be in the LINKLIST or in your STEPLIB.
BPXWRTSO is necessary only for ADDRESS TSO and must be in an APF
authorized library or copied to the HFS in a directory included in
your PATH environment variable as bpxwrtso and marked as APF
(using extattr +a bpxwrtso). If this is kept in an authorized
library or LPA, it will be necessary to create a file in the HFS
called bpxwrtso in a directory in your PATH and mark it as sticky
(use touch bpxwrtso; chmod 1555 bpxwrtso).
BPXWRXEV is the OpenEdition REXX environment module.
This module already exists in SYS1.LPALIB. This module must be
replaced or loaded from your STEPLIB. If you have installed a
previous release of this package and you already installed this in
LPA you must do this again.
BPXWRBLD, BPXWREXC, BPXWREXI, BPXWREXT, BPXWRIO, and BPXWRLD
already exist in SYS1.LINKLIB. These must
either be replaced, loaded from STEPLIB, concatenate this library
ahead of SYS1.LINKLIB in your LINKLIST, or copy these modules to a
library already ahead of SYS1.LINKLIB.
Note that these parts along with the new part BPXWRXFP are now
in a single load module named BPXWREXC. All the other names are
aliases.
The easiest way to install this is to include this load library in
your STEPLIB environment variable and not alter any system libraries.
psw=getpass('enter password') /* prompt for password and read it */
LINEIN
LINEIN([name][,[start][,count]])
line=linein(file) /* read next line */
line=linein(file,1) /* read first line in file */
LINEOUT
LINEOUT([name][,[string][,start]])
call lineout ,'hello world' /* write the line to stdout */
LINES
LINES([name])
more=lines() /* set more to non-zero if stdin has data */
OUTTRAP
OUTTRAP([name][,[max][,catopt]])
call outtrap 'out.',,'NOCONCAT'
REXXOPT
REXXOPT([option][,arg1[,arg2]])
call rexxopt 'immed',sigint /* make interrupt signal prompt for cmd */
SHCMD
SLEEP
SLEEP(seconds)
call sleep 5 /* wait 5 seconds */
STREAM
STREAM([name][,operation[,command]])
call stream name,'c','clearfile' /* empty the file */
call stream file,'c','close' /* close the stream */
fd=stream(name,'c','infileno') /* get file descriptor for the
read side of the stream */
call stream ,'c','nosignal' /* disable halt signal for the
standard input/output stream */
file=stream('mydata.text','c','open write') /* open a stream for the
file mydata.txt */
file=stream('mydata.text','c','open write replace') /* same as above
but will replace the
file if it exists */
fd=stream(name,'c','outfileno') /* get file descriptor for the
write side of the stream */
compcd=stream(file,'c','pclose') /* close get completion code on
the process stream */
pid=stream(name,'c','pid') /* get pid for a stream
opened with POPEN */
file=stream('ls | wc','c','popen read') /* open a pipe stream to the
output from the 'ls | wc' shell command */
say stream('myfile','c','query exists') /* print pathname */
pos=stream(name,'c','readpos') /* get read location in file */
call stream name,'c','readpos' 5*80+1 /* set read location to 6th
80 byte record */
call stream ,'c','signal' /* enable the halt signal for the
standard input/output stream */
say stream(name,'c','size') /* print size of file */
call stream name,'c','writepos <0'/* set position to end of file*/
call stream name,'c','writepos 1' /* set position to start of file */
ADDRESS TSO
General Information
Syntax
address tso [command]
Command Input
Command Output
Return Codes
Examples
address tso 'time'
call outtrap out.
address tso 'listc'
do i=1 to out.0
say out.i
end
address tso
"alloc fi(sysexec) da('schoen.rexx') shr"
"myexec"
/* rexx */
address tso arg(1)
return rc
Notes and Warnings
Installation
History
2/16/97 Initial external release
5/18/97 External release
Added stream command "query exists"
Added stream command "query size"
Added stream open options REPLACE and BOTH
Stream OPEN command now defaults to READ
5/24/97 Internal release
Added rexxopt() function; options: immed, noimmed
Immediate command support (hi, ht, rt, ts, te) on ctl-c
Added shcmd()
10/03/98 External release
Deal with setuid/setgid programs
Add rexxopt(version)
1/03/99 fix shcmd for more than 3 args
add DD: support to shcmd
support long external rexx function names (with TSO PTF)
repackage to include all rexx support for shell env
1/22/99 allow shcmd to have input stems with 0 vars
add BPXWUNIX that works like shcmd but in TSO and give
shcmd alias bpxwunix
7/11/99 fix freemain length: storage leak on external rexx
function calls (base fix in R9: PWY0506)
8/07/99 added convd2e function
8/13/99 shcmd and bpxwunix missing closes for stdout/stderr
5/xx/00 (not released) multiplex file processing for shcmd/bpxwunix
extended stream open syntax, added getpass() function
10/22/00 Address TSO, outtrap()