Safe REXX on the Desktop,

Will They Still Respect My Code in the Morning?

Shmuel (Seymour J.) Metz

(Part 2 of 2 parts)


REXX has some specific features that you can exploit to make your programs more compatible across platforms, or between environments on the same platforms.  REXX also has some features that hinder compatibility.

ADDRESS and the default environment

If you write a command file that issues host commands, ie. OS/2, CMS, TSO, DOS commands, do not assume that the default environment is that of the host itself.  by including ADDRESS CMD in your code, you will enable the routine for use from within other environments, e.g., editors that use REXX as their macro language.

Environmental factors

REXX does not shield you from the underlying environment; in writing a REXX program you must understand the behavior of your operating system and user interface if you want to avoid nasty surprises.  As an example, if you invoke a REXX program in an OS/2 CMD file and scan the argument looking for the string "/Q", you will not find it because CMD.EXE will have taken the string "/Q" to be a "quiet" option and removed it.

If you must use binary or hexadecimal constants for character data, be aware that character encoding varies among systems.  DOS and OS/2 use ASCII, CMS and TSO use EBCDIC.  Even then, the correct value may depend upon the code page or national language in use.  Be aware of the character sets used in each of your target systems, and program accordingly.  Segregate system-dependent values and code page-dependent values to make your code easier to maintain.

I/O model

The I/O model in REXX is based on the file system in the CMS component of IBM 's VM/SP.  Most other systems, like DOS, OS/2, and TSO, do not have an orientation towards line numbers.  For this reason, SAA REXX in OS/2 differs from the REXX standard, in that the LINES function only returns values of 0 and 1.  See Figure 10.  The TSO/E support in OS/390 2.4 does not include charin et. al, and has not been upgraded as of 2.6; however, VM/ESA 2.2 appears to include those functions.  I'm not sure exactly when they came in.  CMS uses EXECIO, and TSO uses a subset of EXECIO.  Note that the CMS option of EXECIO for reading a single line into a simple variable is highly nonportable.  Code written in accordance with the standard may fail in OS/2, and _will_ fail in CMS and TSO.

Further, a faithful implementation could be horribly inefficient if the file system in the host operating system does not maintain line counts.

Figure 10: LINES examples

   /* In standard REXX */
   do lines(myfile)
   /* In OS/2 this would only read one line ! */

   /* In OS/2 SAA REXX */
   do while lines(myfile) /= 0

REXX provides no good way to detect end-of-file.  You could use STREAM(file,"State") and check for a value of "NOTREADY", but there is no guarantee that end-of-file is the only condition causing NOTREADY.

The safest thing is to encapsulate your input/output code and then take advantage of whatever facilities may exist in each target system, e.g., EXECIO with the STEM option, REXXLIB from Quercus.  Any such code should be thoroughly documented.  Be aware that EXECIO in TSO/E supports only the stem and stack forms of EXECIO; it does not support the variable name form.


The PARSE SOURCE statement allows your code to determine the operating system and file from which it was invoked, as well as the type of invocation.  You can take advantage of this in order to maintain a single version of a REXX program for two different systems, to detect inappropriate invocations, to select character encoding, etc.  If you have data files that, by default, should be in the same directory as your code, you can use this statement to locate them.  See Figure 11.

Figure 11: Parse examples

   parse source system invocation origin

      when system = 'OS/2' then do
      when system = 'TSO' then do
      otherwise do
         say system 'is not supported by' origin

   parse version name level date1 date2 date3 .
      when name = 'REXXSAA' then do
         parse var level int '.' frac
         if int > 3 then do
            /* fast code for SAA level 4 goes here */
         else do
            /* slower code for older SAA level goes here */
      when name = 'REXX370' then do
         /* Code for CMS or TSO level of REXX  goes here */
      otherwise do
         say name 'is an unsupported REXX implementation'

The PARSE VERSION statement allows you to determine the language level of REXX that your program has available.  This allows you to write code that exploits new features of REXX, yet include alternate code that will be used when running on an older platform.  See Figure 11.

REXXUTIL and emergency boot disks

If you might want to use your REXX code from an emergency boot disk, include code that does not depend on REXXUTIL.  See Figure 12.  This is because PM is too large to include on an emergency 1.44 MB floppy, and REXXUTIL requires PM.

Figure 12: Boot-disk examples

   if REXXUTIL_loaded then do
      do i=1 to filespec.0
   else do
      'DIR' filespec '/F /O > WORK_FILE'

Variable patterns

If you use variable patterns in the templates of your PARSE statements, be aware that some older implementations of REXX do not support all forms, e.g., in MVS/XA the form "+(variable)" is not available.  It is available in CMS as of VM/ESA 1.2.0 (CMS9) and in MVS/ESA as of TSO/E 2.4.  If you need to run on multiple platforms, check which forms are supported on each and program accordingly.


You can make your use of REXX more enjoyable and productive by following a few basic rules.  Learn REXX on its own terms.  Be careful and consistent in your use of abutment and continuation.  Do not use keywords or single letters as variable names.  Use SIGNAL only for error handling.  Do not attempt to use the same lines as both inline code and out of line code.  Place a PROCEDURE at the beginning of every subroutine, and carefully analyze which variables to expose, especially if you will be passing the names of variables.  Be careful in your use of uninitialized variables.  Adopt a clear and consistent programming style.  Understand the vagaries of REXX parsing.  Try to make your code portable across platforms and usable in multiple environments.

These rules will not, of course, eliminate all errors, but they will certainly eliminate many errors that would otherwise be highly likely.  Good luck, and practice Safe REXX!

Note:  The portability considerations are based on experience with REXX in CMS (VM/SP), DOS (Personal REXX), MVS (TSO/E) and OS/2 (SAA REXX).  I have not used other implementations such as AREXX, Object REXX and Regina.  I welcome comments on portability issues going to or from these other implementations.


    OS/2 Procedures Language 2/REXX Reference, S10G-6268

    OS/2 Procedures Language 2/REXX User's Guide, S10G-6269

    SAA Common Programming Interface Procedures Language Reference, SC26-4358

    TSO Extensions Version 2 REXX Reference, SC28-1883

    TSO Extensions Version 2 REXX User's Guide, SC28-1882

    The REXX Language
      A Practical Approach to Programming
      2nd Edition
      Michael F. Cowlishaw
      Prentice-Hall, Inc.
      A division of Simon & Schuster
      Englewood Cliffs, New Jersey  07632
      ISBN 0-13-780651-5


IBM, MVS/ESA, OS/2, VM/ESA, and VM/SP are trademarks of IBM Corporation. Unix is a trademark of The Open Group.


Shmuel (Seymour J.) Metz, Digital Solutions, Inc. (DSI).  Mr. Metz is a Senior MVS Systems Programmer supporting a Federal Government facilities management contract.  He has worked with computers for 38 years.  He has been involved in the development of two different operating systems.  He has experience on a wide variety of languages and platforms, and has used REXX on four of them.  Mr. Metz has an MA in Mathematics from the State University of New York at Buffalo.

He can be reached at 703-256-4764 between 6:00 PM and 9:00 PM EST, at his office at 703-306-1185, X3095, and as SHMUEL@ACM.ORG on the Internet.

A slightly different version of this article was printed in the February 1995 OS/2 Magazine.

Copyright 1998 by Shmuel (Seymour J.)  Metz.  All rights reserved.  Permission for reproduction in whole or in part is hereby granted to educational, non-profit and computer user groups for internal, non-profit use, provided credit is given and this notice is included.  All other reproduction without the author's prior written permission is prohibited.