Figure 3 - An explanation of the instructions used in the program shown in Listing 2.
- 0001
- The presence of a comment, beginning in position 1 of line 1 tells cmd.exe that this is a REXX program rather than a procedural .cmd batch command file.
- 0002-0004
- As in the Say Hello example, these two lines write messages to the console. The PULL instruction then waits for you to key in a letter and press <Enter>.
The value entered is "assigned" to the "variable" drive_letter. An assignment clause is one of the most commonly used type of REXX clauses.
A variable is a symbol whose value may be changed during the course of execution of a REXX program.
- 0006
- Another assignment is made, only this time it involves assigning two values together to the variable config_sys_file_name or "concatenating" the value contained in the variable drive_letter to the a value of ':\CONFIG.SYS' (a "literal").
If you had entered a lower or upper case C when the program asked for a response, the resulting value in config_sys_file_name would be 'C:\CONFIG.SYS'. The apostrophes, or loosely-called quotes, are not included in the actual value.
The PULL instruction has an implied function of uppercasing the value when it is read from the keyboard.
- 0007-0011
- This group introduces a number of REXX instructions and clauses. Its purpose is to check to make sure that the file actually exists. If it does not, then the user is informed via the message "Unable to locate ?:\CONFIG.SYS", where ? represents the letter the user entered, and the program is terminated.
- 0007
- REXX has a rich collection of "functions" which are used for different purposes. STREAM() is one such function and it has a number of options that make it perform differently. In this case, we are using the function in an "expression" and testing the evaluated expression to see if it is equal to a null - the value which is returned if the file does not exist.
This is similar to using IF ... EXISTS in a DOS or OS/2 batch command file.
The test is made using the IF THEN combination and the group of instructions between the DO and END instructions is executed if the evaluation is equal or true.
- 0008-0009
- A message, indicating the reason the program is terminating, is written to the console and control is returned to CMD.EXE with the EXIT instruction.
- 0013-0014
- The two assignments place the value of a printer form feed and a numeric value of zero in the variables form_feed and input_line_count respectively.
D2C() is another built-in REXX function. It is used to convert a decimal value to its actual character value. In this case a decimal value of 12 results in the pre-defined form feed control character of '0C'x.
- 0015-0019
- This group of instructions, bounded by DO and END instructions similarly to the group in lines 0008 - 0011, reads a line from config.sys and assigns the value of that line to the variable input_line, increments a tally of the number of lines written and then writes that line to the printer.
The use of the LINES() function in the conditional statement in line 0015 causes this group of instructions to iterate until all of the lines in CONFIG.SYS have been processed. At that time, the DO loop is complete.
- 0020
- To keep the listing neat, a form feed character is sent to the printer to cause a continuous forms printer to skip up to the beginning of a new page or a laser printer to eject the printed page.
Note that the actual printed line was sent to the printer with the LINEOUT() function whereas the form feed character is sent to the printer with the CHAROUT() function. The difference is that LINEOUT() cause the line to be written to the output file or device with a terminating CR/LF pair (carriage return / line feed) combination. CHAROUT() sends only the specified characters without appending anything to the data.
- 0022-0023
- The housekeeping function of "closing" both the input and output files (yes, the printer is handled just like a disk file except that a form feed will not cause your hard drive to skip to a new page).
- 0025-0026
- The number of lines that were processed is written to the console. Line 0025 uses "abuttal" concatenation to cause the two values, the variable input_line_count and the literal value, to be written to the console.
The use of the double bar or abuttal concatenation prevents a space from being inserted between two values which is what would occur if the || were not there.
The blank lines which contain just a sequence number in Figure 3 were inserted simply
to make the program more readable.
As you can see, writing a simple REXX program is not a difficult task. The secret to
making REXX really perform for you is knowing the available functions that are at your
disposal. The on-line REXX information file contains the definition of most of the functions
contained in OS/2 SAA REXX and its REXXUTIL external function module. A complete
reference for all of the REXXUTIL functions can be found in the REXX Reference Summary
Handbook.
Because of its simplicity, REXX is very easy to abuse. I recommend to both new REXX
programmers as well as veterans that they take the extra time and effort to write all of their
REXX programs as if they were intended to be read by others. Use meaningful labels for
variables rather than abbreviations that will be meaningful to you but that will be
undecipherable by anyone else.
Use appropriate spacing and column alignment to make your program more pleasant
to the eye. This makes it more comfortable for a stranger to follow the logic of your program.
Don't skimp on comments that provide an overview for groups of related instructions.
In summary, your programming style can sometimes be as important as your program
functionality.
Undocumented Warp function
A pair of environment variables were added to Warp but are not contained in the
Warp online documentation. SET BeginLibPath= and SET EndLibPath= provide the
capability to dynamically alter the current session's value of LIBPATH as it is defined in
config.sys. Both SET statements are followed by one or more path names which are to be
inserted into the beginning and end of the LIBPATH string for the current session,
respectively.
These two environment variables are handled uniquely by cmd.exe. This fact has
special significance to a REXX program that wants to either set, or retrieve and parse these
two variables.
First, though both of the environment variables can be set using the VALUE()
function, they will not serve their intended purpose since the VALUE() function was not
updated to include the special use intended for these values. Therefore, contrary to the
recommended use of a REXX function to set an external value (rather than passing the
equivalent command to cmd.exe); there is no alternative if it is necessary to set either
environment variable from within a REXX program other than to pass the SET command
to cmd.exe.
Secondly, the string returned from SET BEGINLIBPATH will not contain any spaces
before or after the equal sign (SET BEGINLIBPATH=?:\...) whereas the result returned
by a SET command by itself will contain a space both before and after the equal sign (SET
BEGINLIBPATH = ?:\...).
The incompatibility of the VALUE() function is a program defect which I have
reported to the appropriate group in IBM.
Conclusion
In future columns I will cover many of the features that experienced REXX users
take for granted as well as some of the lesser known capabilities of REXX and the external
function packages available for OS/2 REXX use.