Professional Documents
Culture Documents
Table of Contents
Introduction . . . . . . Goals of the course. . Uses of REXX; what is a REXX program?. . . CLIST vs. REXX . . . . How does TSO know the difference?. . . . . What is REXX?. . . . . 3 4 5 6 7 8 Error handling Interactive debugger Trace options . . . . EXECUTIL. . . . . . . Error traps . . . . . Examples. . . . . . . . . . . . . . . . . 40 40 41 42 43 46
Getting Started 10 Allocating REXX files. 10 Connecting your execs to your session. . . 13 Get on with it! General syntax . . . REXX keywords. . . . Variables and labels Literals . . . . . . SAY instruction. . . REXXTRY exec . . . . . . . . . . 14 14 17 18 20 22 22 23 23 25 27 28 29 30 30 32
Arithmetic 49 Arithmetic operations . . 49 Precision . . . . . . . . 50 Control Structures 51 SELECT instruction. . . . 51 Looping . . . . . . . . . 53 Talking to the environment 57 What environment? . . . . 59 Edit macros . . . . . . . 61 Modular programming in REXX Functions and subroutines Some built-in functions . User-written functions Internal. . . . . . . . External. . . . . . . . Compound (stem) variables TSO Interactions Messages and OUTTRAP. The stack . . . . . . NEWSTACK and DELSTACK TSO and the stack . . . . . . . . . . 62 62 63 67 68 71 74 77 77 79 81 83
Real REXX coding Variables. . . . . . . Concatenation. . . . . Conditional operators. DO groups. . . . . . . Approximations . . . . Boolean operators. . . Evaluating expressions Passing data (ARG) . .
Page 90 page 92: examples of REXX code page 96: answers to questions Page 106: solutions to exercises complete list of REXX built-in functions (with separate page numbers and TOC). 2
Introduction
There are two basic types of programming languages: compiled and interpreted. The first kind, such as COBOL or Assembler, must pass through two steps. The first step converts text (your source code) into object code, something the machine can understand. The second step converts the object code into an executable module. Only then can you see if your program runs. TSO CLISTs and the original BASIC language are interpreted. An interpreted language runs the source code directly, one line at a time. You can do a lot with CLISTs, but they have some annoying quirks. There are also some things you just cant do in a CLIST. On the other hand, COBOL works with machine and data files and doesnt have user friendly interfaces. Assembler, while extremely powerful, is somewhat obtuse. What we programmers like to see is a language thats user-friendly, so we can quickly write workable programs. It should be easy to read, so nearly anyone can write a tool or debug an existing one. It must be fully functional, so no additional programming is needed. Finally, it must be portable so you can run it anywhere. There is such a language; its called REXX. To program in REXX in zOS, you need three things. You should be somewhat familiar with TSO commands. You should be somewhat familiar with the ISPF editor. You should have some experience with a symbolic language.
CLIST
PROC 1 DSN ALLOCATE FILE(A) DA(&DSN)
REXX
/* REXX program */ Arg DSN ALLOCATE FILE(A) DA(DSN)
Trivia
CLIST is an acronym for Command LIST. REXX is an acronym for Restructured EXtended eXecutor.
Questions
What language is this program written in?
10
10
11
ISPF Library: Project . . Group . . . Type . . . . Other Partitioned, Sequential or VSAM Data Set: Data Set Name . . . my.rexx.exec Volume Serial . . . (If not cataloged, required for option "C") Data Set Password . . (If password protected)
Option A or M for Allocate. Key in the name to allocate (here, MY.REXX.EXEC). Hit ENTER.
11
12
Management class Storage class . Volume serial . Device type . . Data class . . . Space units . .
Average record unit Primary quantity . Secondary quantity Directory blocks . Record format . . . Record length . . . Block size . . . . Data set name type
(LIBRARY, HFS, PDS, or blank) * (YY/MM/DD, YYYY/MM/DD YY.DDD, YYYY.DDD in Julian form DDDD for retention period in days or blank)
( * Specifying LIBRARY may override zero directory block) ( ** Only one of these fields may be specified)
Fill in as shown: Five tracks are enough for this class. My own current REXX PDS is only two cylinders. Ten directory blocks is forty members or so. RECFM = VB, LRECL = 255.
12
13
Now save the program. Congratulations, youve written your first REXX exec!
13
14
1. 2. 3. 4. 5. 6.
*/
REXX does not have line numbers per se. The REXX interpreter keeps track of line numbers, which may be displayed when an error message occurs. When editing a REXX exec, your edit profile should be NUMBER OFF. Remember, a REXX exec must have the word REXX somewhere on Line 1. It doesnt have to be first, although that is a typical convention. Comments in REXX begin with a /*, and must end with a */. REXX does not close the comment until it finds a */. For example, this is a long comment line:
/* REXX long comment: the C = A + B wont be executed because its considered part of the comment: C = A + B */
Line 2 puts a value of 1 into A. What does Line 4 do? Line 5 displays
The answer is 3
on the terminal. Line 6 ends the program.
14
15
EXIT 10
passes a 10 back to the calling program. You can test this with the WHEN TSO command, or as a variable. In a CLIST, the variable &LASTCC contains the return code. In a REXX exec, the variable RC contains the return code.
Questions
What does a REXX exec always start with?
/* X = Y = Z = Say
15
16
Say Hello
This is a box comment. Note each line is not closed. Only the first and last lines have slashes; the first slash starts the comment, and the last finishes it.
/* multiple-line comments are more efficient than many single-line comments. So, when making comments like this, use one pair of comment delimiters. */
REXX execs have one statement per line. You can continue a statement on a second line by ending the first part with a comma:
Say, Next?
You can also have multiple statements on a line by separating each statement with a semicolon:
Say AARGH produces AARGH Say Aargh produces Aargh SAY AaRgh produces AaRgh
16
17
REXX Keywords
Keywords: SAY, DO, IF, EXIT Literals: Moe, Larry, Curley, 1234, 9876 Variables: A, XYZ, DSN, MyFileName Assignments: A = B Command: ALLOCATE, DELETE, LOGOFF
A literal is itself. It doesnt stand for anything. Unassigned variables are considered literals. For example this program produces two lines of output, shown below.
/* REXX */ Say Curley Curley = 2 Say Curley READY <rexx name> Curley 2 READY
17
18
REXX Variables
Variables contain information. They stand for another thing. For example, in this statement
A + B
A and B are variables containing numbers (you cant add A and B). Anything starting with a word REXX does not understand is taken to be a TSO command and given to TSO. Assignments are understood by REXX and are not sent to TSO. SAY is understood by REXX, so REXX carries out the instruction. DELETE is not understood by REXX and is sent to TSO for processing. To send something directly to TSO, put quotes around it and put it first on the line (or after an IF). For example, these REXX statements do the same thing:
ALLOC F(A) DA(MY.JCL) SHR REUSE ALLOC F(A) DA(MY.JCL) SHR REUSE
The type of quotes does not matter, as long as the start and end quote characters match. As a general rule, I use double quotes because fully-qualified dataset names use single quotes. At times the type of quotes does matter. Well cover those instances as we continue.
REXX Labels
Labels name a subroutine, user-written function, target of a transfer-of-control instruction, or error trap. The label must be the first thing on a line, followed by a colon. The label can be on a line by itself.
COMPUTE:
C = A + B
COMPUTE: C = A + B
18
19
Questions
Do these use the correct syntax? If not, whats wrong with them?
1 - Say Eat; Say At; Say Joes. 2 Say Hey; Say; Man 3 - Compute; C = Y - A
True or false: you can go to a label.
True or false: the EXIT statement must always be the very last line in the program.
19
20
Say Oh no! displays Oh no! Say Oh no! displays Oh no! Say Oh no! displays Oh no! plus everything that follows up to
the next single quote, or produces an error if more than 250 characters lie between single quotes. If you forget quotes, it usually works anyway. REXX checks to see if its a variable. If something has been assigned to it, thats what you get. If there is nothing assigned to it, REXX assumes you meant a literal. REXX does not try to evaluate literals. If the literal is first on a line, REXX sends it to TSO. For example,
LISTCAT
The null string is represented by or . The maximum size of a literal is 250 characters. Numeric literals may have quotes, unlike COBOL. These are all valid:
A = 1 B = 2 C = A + B + 3
C contains 6.
If theres an E in the number, its scientific notation. For example, 2E+4 is 2 times 10 to the fourth power, or 20,000. Literals can be hex strings. Hex characters must be in quotes, with an X after the last quote. For example,
Say F1F2F3X
produces 123 as its output.
20
21
A Pitfall
Anytime you put an X after a string, REXX takes it as a hex string. Look at this example.
Literal Questions
What does this program do?
*/
/* REXX TRY ME THREE */ Greeting = Go Away! Say Greeting Drop Greeting Say Greeting
Exercise #2
Write an exec to display these three lines:
3 + 1 is 4 3 + 1 is 4 OBrien
21
22
Say 5 - 3
What does this display on the terminal?
SAY 5 3
What does this display on the terminal?
SAY 5 3
22
23
The Variable
Variables: Contain information. Stand for that information, which may vary. Is not the information itself. Has a name you choose. Name must start with a letter. Name can be up to 250 characters long, with no blanks in the name. Mixed upper- and lower-case letters are OK. No hyphens, parentheses, quotes, equal signs, or apostrophes are allowed. However, underscores are OK for readability. A period in the name indicates a compound variable (advanced topic to be discussed later in the course). Variables are given values through: Assignment (e. g. A = 5). PULL (input from terminal). ARG (data entered at run time). PARSE (string manipulation). EXECIO (file access). LISTDSI and other TSO commands and functions. A variable never given a value is considered a literal.
23
24
24
25
25
26
Concatenation
To display or connect variables you can just put them next to each other. If they are separated by any number of spaces, they are connected by a single space. For example:
Say Hi
- or -
Fred
Either results in the display Hi Fred. If you dont specify spaces in between the values, you get no space between the results. However, you do get an extra quote.
26
27
More on Concatenation
The concatenation operator is two vertical bars: ||. Here are some examples of concatenation, both with and without the bars:
1.Var1 = Up 2.Var2 = Away 3.Var3 = per 4.Var4 = son 5.Say Var1 Var1 and Var2 6.Say Var1 Var1 and Var2 7.Say Var1 Var1 and Var2 8.Say Var2 Var3 Var4 9.Say Var2 Var3||Var4 10. Say Var2 Var1||Var3 Var4
The results of the Say statements are:
5.Up Up and Away 6.Up Up and Away 7. Up Up and Away 8.Away per son 9.Away person 10. Away Upper son
The concatenation operator is needed only when concatenating two variables. There is no need to use it when concatenating literals with variables.
Say Elle
||
Woody
When this prints, how many spaces are between Elle and Woody?
Say Elle
Woody
27
28
Conditional Operators
As in all programming languages, REXX has an IF statement. The statement follows a standard format.
> < = ==
<>
Greater than Less than Numerically equivalent, e. g. 001 = 1. Strings are equivalent when padded with blanks (e. g. New York = New York ). Equal in every way. For example: 001 == 001 True 001 == 1 False New York == New York False Not equal
You must use the symbols. For example, you cannot code
If A greater than B
28
29
If A = B Then Do A = B 1 Say A was equal to B, but now its not. End If A = B Then Do Say A is equal to B. Say B is equal to A. End Else Say A is not equal to B.
DO groups are quite flexible, may be nested, and can be run multiple times. Well talk more about DO groups later in the course.
29
30
Inexact Comparisons
1000.0001 is pretty close to 1000. In normal mathematics, the two are not equal. With the REXX instruction NUMERIC FUZZ, they can be equal. The syntax of the FUZZ instruction is:
Numeric Fuzz 1
*/
9 significant digits is the default. REXX normally looks at all significant digits. FUZZ tells REXX to ignore the least significant digit or digits. Here are some examples:
Numeric Digits 5 /* set to five sig. digits */ Numeric Fuzz 1 If 12361 = 12362 Then Say Equal /* FUZZ says ignore least significant digit */ If 02361 = 02362 Then Say Not Equal /* there arent 5 significant digits
*/
Numeric Digits 4 /* set to four sig. digits */ Numeric Fuzz 1 If 02361 = 02362 Then Say Equal /* FUZZ says ignore least significant digit */
Exercise #4
Write an exec to: Store the number 15 as a constant; Store the number 19 as a constant; Write the instructions to compare the numbers and find them equal.
30
31
Boolean Operators
Boolean operators allow more than one compare on one statement. The standard operators are:
& is AND, both must be true. | is OR, either or both are true && is Exclusive OR, one or the other is true, but not both. If Me = Hungry & Food = On Table Then Say Im on a see-food diet. If Today = Saturday | Today = Sunday Then Say Honey, where are my golf clubs? If What = Cake && How = Eat it Then Say Cant have your cake and eat it too Evaluation of Expressions
A comparison is an expression too. If the comparison is true the value is a 1. If the comparison is false it becomes a 0. For example,
Say 1 = 2
displays 0 because the comparison is false.
Be careful! A = B = 2
checks to see if B = 2. If it is, it produces a 1, so A is set to 1. If its not, A is set to 0. The value in B is not affected.
31
32
A Specific Example
Heres something you wouldnt do, but it shows how REXX works.
ABC = CDE
REXX processes it as: ABC is not a REXX keyword. Its not an assignment. Not a TSO command because of the =. Taken as a comparison. Is ABC = CDE? It isnt, so the value becomes 0. The line thus becomes 0. REXX doesnt understand 0, so it gives it to TSO. 0 is not a valid TSO command. Running this produces a TSO error message IKJ56621I INVALID COMMAND NAME SYNTAX
32
33
/* REXX MYP exec */ ARG LASTN FIRSTN SCHOOL SAY FIRSTN LASTN at SCHOOL MYP Conda Anna Yale
When you execute a program, you can pass it information on the command line after the name of the program. Any information on the command line is passed to the program. REXX picks this information up with the ARG command. Thus, the above program produces:
Exercise #5
Write an exec to execute the LISTCAT ENTRY(dsn) command. Pass the DSN using ARG. Make sure it works on your own datasets and datasets not belonging to you.
33
34
MYP Conda Anna /* REXX MYP exec */ ARG LASTN FIRSTN SCHOOL SAY FIRSTN LASTN at SCHOOL Anna Conda at
MYP Conda Anna La Salle /* REXX MYP exec */ ARG LASTN FIRSTN SCHOOL SAY FIRSTN LASTN at SCHOOL Anna Conda at La Salle
MYP Conda Anna La Salle /* REXX MYP exec */ ARG LASTN FIRSTN SCHOOL . SAY FIRSTN LASTN at SCHOOL Anna Conda at La
34
35
Exercise #6
Write an exec to accept three pieces of information and display them in reverse order of entry. If more than three are entered, display an error message.
Exercise #7
Write an exec to examine information passed to it. Perform the following checks. If Al is entered, display Must be a Liberal. If Rush is entered, display Gotta be a Conservative. If both Al and Rush typed in, display Look out!. If neither given, display an error message.
35
36
The template is a mask or filter through which data must pass before being distributed to the variables. The template may be: Just the variables. Columns (where columns are the delimiters). Literals (literals are the delimiters).
All forms of PARSE place the information into variables. They all work the same way, the only difference being the origin of the data. All the variables in the template are changed. PARSE is sometimes used in short forms: ARG is the same as PARSE UPPER ARG; PULL is the same as PARSE UPPER PULL.
36
37
Literals in a Template
All the templates weve seen so far were just a list of variables. You can tell REXX how to distribute information into variables. That gives you more control over how information is passed to the exec. Consider this:
ONE = HOW; TWO = ARE; THREE = YOU TODAY REST = HOT ISNT IT?
Anything before the literal is stored into the leading variable(s). Anything after the literal goes into the trailing variable(s). You can use a variable containing a delimiter. Consider this:
%RUNIT THERE ARE TWO AND 1 / 2 DOZEN EGGS. SLSH = / PARSE ARG ONE TWO THREE (SLSH) REST
To use a variable, enclose it in parentheses. In this example the variables become
ONE = THERE; TWO = ARE; THREE = TWO AND 1 REST = 2 DOZEN EGGS.
37
38
Question
If you execute the exec with the command shown, what are the results?
%RUNME JOHN 1313-1/2 DEADEND ROAD /* REXX Runme */ Arg YOUR_NAME ADDRESS / JUNK Say Your name is YOUR_NAME Say You live at ADDRESS
Exercise #8
Write an exec to accept two arguments: the day of the week and the weather. If the day is Friday and the weather is rainy, display Head for office!. If the day is Friday and the weather is not rainy, display Go Rock Cats!.
38
39
Say Enter your name, please: PULL NAME Say Thank you, NAME
Be careful. If there is something in the TSO stack, PULL takes that and you wont get what was typed at the terminal. There is a way to get around that, shown below. Dont worry; well get more into the stack later. For now just be aware of it.
/* Something may be in the stack now; NEWSTACK saves the old stuff in the stack */ NEWSTACK Say Enter your name, please: PULL NAME Say Thank you, NAME /* Delete new stack (restores old stack) */ DELSTACK Avoiding the Stack Problem: PARSE EXTERNAL
The PARSE EXTERNAL command gets the line directly from the terminal. That means you dont have to worry about whats in the stack. The syntax is:
39
40
Question
You want the user to enter three, and only three, items of information separated by spaces. What does your PULL look like?
Exercise #9
Write an exec to ask for three, and only three, words and display them in reversed order.
Exercise #10
Write a front end exec for the DELETE command. Have it ask, Are you sure?. If the dataset name is junk.data, dont ask.
Exercise #11
Write an exec to compute the percent increase of one number over another. Ask for the two amounts from the terminal. The formula is: % increase = 100 * ((new old) / old) Imagine your old salary was $34,000 and your new salary is $80,000. You would calculate your percent increase as: 100 * ((80000 34000) / 34000)
Exercise #12
Ask for the weather and the day of the week from the terminal. If its raining, ask how many inches are expected. If its Friday and sunny or cloudy, display Head for the golf course! If its Saturday and less than .5 inches, display Fishing pole, please!
40
41
If you just press ENTER after PA1 or ATTN, the exec continues. You can trace the execution of your exec. There are many options to trace; these are described on the next page. You can code most trace options (including EXECUTIL statements) inside a REXX exec. Youd probably remove them when the exec has been released to the general public. Main programs and their subroutines do not share tracing settings.
You can specify the abbreviation shown above, or the full word (e. g. TRACE NORMAL).
41
42
Tracing Options
Least amount of things traced TRACE ! TRACE O TRACE N TRACE F TRACE E TRACE !C TRACE C TRACE L TRACE A TRACE S TRACE !R Nothing traced, dont execute any commands. Nothing traced. Normal, TSO/CMS commands failing or erroring out are traced. Failure, non-existent or abending TSO/CMS commands Error, non-working TSO/CMS commands Trace commands but dont execute them Commands, TSO/CMS commands Labels only All (labels, commands, REXX verbs) Scan labels, commands, and REXX verbs Results for labels, commands, REXX verbs, or any time a variable is changed, but dont execute any commands Results for labels, commands, REXX verbs, or any time a variable is changed Results for labels, commands, REXX verbs, or any time a variable is changed with interactive debug Intermediate, labels, commands, REXX verbs, or any time a variable is changed, showing intermediate results (e. g. C = (4+3) * 2), and dont execute commands. Intermediate, labels, commands, REXX verbs, or any time a variable is changed, showing intermediate results (e. g. C = (4+3) * 2)
TRACE I
42
43
Using EXECUTIL
EXECUTIL TS turns interactive debugging on within the exec. There is no special reason for doing this in an exec, TRACE ? works. EXECUTIL TE turns interactive debugging off within the exec. There is no special reason for doing this in an exec, TRACE OFF works. EXECUTIL HT stops the display to the terminal. EXECUTIL RT restarts the display to the terminal.
Interactive Debugging
During interactive debugging, your exec stops. You can do these things: Execute one instruction at a time, using the ENTER key; Display or change variables; Turn tracing on or off; Re-execute the most recent instruction by typing the = key. You might want to do that if you changed a variable and want to see if it works now. Type and run any instruction you could put into your exec: o Display variables: Say AH o Change variables: AH = 9 o Send commands to the environment :
Questions
Your program is running, apparently not doing anything, and wont stop. What do you type in to see what its doing? Youre in interactive trace, single-stepping through the program, and want to quit. What do you type in to get the program to complete without further tracing? Can you regain control of a runaway program by typing EXECUTIL TS? 43
44
Error Trapping
REXX allows five types of error trapping routines. There are two types of error trap. One quits the program, the other continues running from the point of the error. Well take a look at both. Some errors should halt the program. The program should inform the user of the error before shutting down. Error traps are generally set up at the beginning of the program. Conditions occurring after that are intercepted wherever they happen. Control jumps to the error handling routine. Usually the routine contains an EXIT. Here is the syntax:
*/
The other type of error traps are subroutines. Control returns to the instruction immediately after the one causing the error. You may not return anything. The RESULT variable is not set. Here is the syntax.
*/
You can name the routine if you want to, as in this example.
Call on condition,
NAME routine_name
routine_name:
: :
*/
44
45
Say D2X(ABS(RC))
If you dont have a FAILURE trap, REXX displays the failed command and continues with the exec. NOVALUE: remember, it is legal to use undefined variables; REXX considers them literals. However, you may want to catch that. This is useful in debugging, but after the program works there is no need to leave it in. If you dont set up a NOVALUE trap, undefined variables are seen as literals. PA1/ATTN: capture the user hitting the ATTN or PA1 keys. If you dont set a HALT trap, hitting PA1 or ATTN, then typing HI, ends the exec. Dont prevent the user from stopping execution! On the next page are some examples of each trap.
45
46
Trapping Examples Signal on Syntax Call on Error Signal on Failure Call on NoValue Call on Halt : : Syntax: Say Syntax error Exit Error: Say Command failed Return Failure: Say Oops! Say Error code is D2X(ABS(RC)) Exit NoValue: Say Please define your variables Return Halt: Say Want to stop now (Y/N)? Pull REPLY If REPLY = Y Then Exit Return
To turn off the error trap, use OFF instead of ON:
46
47
The Infamous Go To
As you may have guessed, SIGNAL can send to a label, even without an error condition. This is the equivalent of the GOTO. If you do use SIGNAL as a GOTO, it should go to an exit point. Do not use SIGNAL to exit loop structures or subroutines as it destroys loop or subroutine structure. There are better ways to exit subroutines.
47
48
Examples of Condition Traps /* REXX sample showing condition traps Call on ERROR Signal on SYNTAX Signal on FAILURE DELETE NO.SUCH.DATASET WHAT COMMAND IS THIS SALARY-INCREASE = 10 Say ERROR_MESSAGE Exit ERROR: Say Command to TSO did not work on line SIGL Say Command was SOURCELINE(SIGL) Return SYNTAX: Say Syntax error on line SIGL Say Instruction was SOURCELINE(SIGL) Say REXX error message: ERRORTEXT(RC) Say Problem is in: CONDITION(D) Exit FAILURE: Say Command to TSO did not work on line SIGL Say Command was SOURCELINE(SIGL) Say Abend Code was RC If RC = -3 Then Say Command not found. Exit */
48
49
Questions
Should you leave error traps in execs going into production? How does the NOVALUE trap help enforce good programming practice? ERRORTEXT(RC) is used in which error trap?
Exercise #13
Write an exec asking for a dataset name. It then issues the TSO command LISTD on it. Set up an error trap to intercept the command not working. In the error trap, display the line of the program in error, the string producing the error, and the error code from TSO. Ask for the dataset name again, re-execute the command, and exit.
49
50
Operators + * / % // **
Add, as in 1 + 1 = 2. Subtract, as in 1 - 1 = 0. Multiply, as in 2 * 3 = 6. Divide, as in 4 / 2 = 2. Integer divide, as in 5 % 2 = 2. Remainder, as in 5 // 2 = 1. Raise to a power (whole numbers only), as in 3 ** 2 = 9. Negative exponents work, but fractional exponents are error conditions.
A - (minus sign) just before a number indicates a negative (e. g. 1). A + (plus sign) just before a number indicates a positive number (e. g. +1). Use parentheses to group numbers, e. g. (5 + 2) * 3 = 21.
50
51
Arithmetic Precision
REXX can do math to almost any precision, and very quickly. You can run out of memory using too great a precision. The default precision is 9 digits. Try the following on your own machine:
/* REXX precision testing */ Say 2 / 3 /* displays .666666667, 9 digits */ Numeric Digits 100 Say 2 / 3 /* displays: . 66666666666666666666666666666666666666666666666 66666666666666666666666666666666666666666666666 66666666666666666666666667 */
While Ive never tried a huge number, NUMERIC DIGITS 10000 has worked for me (its kind of fun to see all those sixes). A while back we talked about FUZZ as a way to approximate values. For example, NUMERIC FUZZ 1 ignores the least significant digit. TRACE I shows all intermediate results of mathematical operations. NUMERIC FORM SCIENTIFIC gives 1.23E+13 NUMERIC FORM ENGINEERING gives 12.3E+12
Exercise #14
Write an exec asking for two numbers, and then multiply them. Set an error trap to intercept any error such as invalid numbers.
Exercise #15
Write an exec asking for an LRECL and a BLKSIZE, then determine if the BLKSIZE is an even multiple of the LRECL. Tell the user if it is or is not.
51
52
Select When DAY = 1 Then Say Sunday When DAY = 2 Then Say Monday When DAY = 3 Then Say Tuesday When DAY = 4 Then Say Wednesday When DAY = 5 Then Say Thursday When DAY = 6 Then Say Friday When DAY = 7 Then Say Saturday Otherwise Say Unknown day of the week. End
52
53
Another SELECT Example Day_Off = No Select When DAY = 1 Then Say Sunday When DAY = 2 Then Say Monday When DAY = 3 Then Say Tuesday When DAY = 4 Then Say Wednesday When DAY = 5 Then Say Thursday When DAY = 6 Then Do Say Friday! Day_Off = YES End When DAY = 7 Then Do Say Saturday Day_Off = YES End Otherwise Say Unknown day of the week. End
Exercise #16
Write a metric conversion exec. The exec should accept two arguments: UNIT and QUANTITY. UNIT can have one of these possible values: LITER, QUART, MILE, or KILOMETER. It returns the equivalent of Quantity in the other measurement system based on this table. 1 1 1 1 liter quart mile kilometer = = = = 1.057 quarts 0.946 liters 1.6 kilometers 0.625 miles
53
54
Do End
instructions
This runs the group of instructions once. There are several modifiers you can use with the DO group to make the group run more than once, or even not at all. If you want to run the loop a specific number of times, code a number. For example, this DO group runs 3 times:
54
55
More DO Loops
You can step through a variable for a DO loop. This is useful for going through a table:
Do I = 1 to 10 Say Number of times through loop: I End EndLoop = 10; Y = 1 Do Z = 1 to EndLoop By 2 Say Loop counter is: Z Say Number of times through loop: Y Y = Y + 1 End Say Countdown: Do J = 10 to 1 By -1 Say J End
55
56
Do Forever If TIME() > 12:00:00 Then Leave Say Is it lunch time yet? End
LEAVE gets you out of the loop. In any loop you may encounter a condition such that, while you dont want to leave the loop, you also dont want to execute the rest of the instructions in it. REXX has a way to do that. The ITERATE instruction tells REXX to never mind the rest of the loop, go back to the top, increment, and continue from there. Heres an example for those not liking the number 13.
I I I I I I I I I I I I I I
is is is is is is is is is is is is is is
1 2 3 4 5 6 7 8 9 10 11 12 14 15
56
57
Questions
What is the ending value of I in this example? Run it to find out.
What is the result of running this after 12:00 noon? Run it to find out (but please dont do so until 11:59!).
Exercise #17
Write an exec asking the user to enter a series of numbers, never the same one twice in a row. Limit the list to 10 numbers.
57
58
/* /* /* /*
58
59
Questions
Will this line of instruction be passed to the environment?
DELETE ABC.DATA
Can you talk to ISPF from any EXEC?
59
60
REXX tries to figure out what kind of command the statement is. It then determines who should execute the statement. All unknown commands are passed to the environment. Using quotes tells REXX to send the statement directly to the environment.
60
61
ADDRESS ISPEXEC DISPLAY PANEL(MEDMENU) VPUT (DOG CAT) SHARED ADDRESS TSO DELETE ABC.DATA
You cannot address ISPF from READY mode because the ISPF environment isnt available. In REXX you can find out whether an environment is available using the SUBCOM command. A return code of 0 means that environment is available.
SUBCOM ISPEXEC If RC = 0 Then NOP /* In ISPF, so continue */ Else Do /* Try again, using ISPF */ ISPSTART COMMAND(this command) Exit End
Note the EXIT in the ELSE loop. This is needed because otherwise the exec will continue to execute. Another way to tell if ISPF is active is this code.
61
62
/* REXX macro converts lower to upper case */ Address ISREDIT MACRO C P< P> ALL Exit Question
Is the environment ISPEXEC always available?
Exercise #18
Write an ISPF edit macro to save and execute the exec youre currently working on. It must start with the usual comment, and then have ADDRESS ISREDIT MACRO (see above). The commands to pass to the ISPF editor are:
63
Say REVERSE(ABCD)
displays DCBA. A function may be called like a subroutine. When done in this way, the result of the function is placed in a special variable called RESULT. For example,
Say TIME()
A complete list of functions can be found in the attachment to this class, and in Book Manager and other IBM documentation.
A Pitfall
If you leave a space between the function name and its data items you dont get the function, you get concatenation.
Length ABCDEF
63
64
Say Length(Kitty)
displays 5
LEFT(string,length): get the left-most length characters of a string. A related function is RIGHT, which gets the rightmost characters.
POS(string1,string2,start_pos): returns the location of string 1 in string2, or a 0 if string1 is not found in string2. The search begins at start_pos. If start_pos is not provided the search begins at the first character.
If POS(,dsn) = 1 then Say Fully Qualified Say POS(rop,Quadrophenia) displays 5. Say POS(rop,Quadrophenia,6) displays 0.
SUBSTR(string,start-pos,length,pad): returns the indicated portion of string starting at start_pos for length characters. If the original string is shorter than the length requested, pad the new string with the pad character.
Say SUBSTR(REXX is Fun!,9,3) displays Fun Say SUBSTR(REXX is Fun!,9,5,!) displays Fun!!
64
65
Say STRIP( Who Are You? ) displays Who Are You? Say STRIP(FULL.NAME.DSN,,)
displays FULL.NAME.DSN
Say STRIP(FULL.NAME.DSN,L,)
displays FULL.NAME.DSN WORD(string,n): displays the nth word from string.
displays on
WORDPOS(phrase,string,start_word): searches for phrase in string beginning at start_word. If start_word is not provided, the search begins at the first word. Say WORDPOS(Hi,Hi ho, Hi ho, its off to work we go,2) displays 3 USERID(): returns the user ID of the person running the exec. TRACE([trace_value]): returns the current trace setting. If trace_value is supplied, the current value is returned and the trace setting is changed to trace_value.
65
66
A B L M N S U W X
alphabetic bits lower case mixed case number symbol (valid symbol, e. g. $, @) upper case whole number hexadecimal number
DATE([option]): If option is omitted the format of the date is DD MMM YYYY. Valid types are:
C D E J O U W
number of days so far this century number of days so far this year European date format (dd/mm/yy) Julian date (yyddd) ordered date, sortable (yy/mm/dd) USA date (mm/dd/yy) weekday (e. g. Friday)
66
67
Exercise #19
Write an exec to accept two numbers from the terminal. Verify they are valid numbers. Subtract one from the other, drop the sign, and display the answer.
Exercise #20
Write an exec see if a dataset called WORKSHOP.TEMP exists. If so, delete it. If not, allocate a new one like your EXEC library. The TSO command is:
68
The benefit is the ability to use the function internally or externally with minor change. It also makes the program more modular. That in turn makes the program easier to debug. A function/subroutine can be either internal (within the same program) or external (in a separate file). Internal and external functions are called the same way. REXX looks for internal functions first. If you use quotes, REXX looks externally. For example:
Say MYSUBR(123)
You can write traditional subroutines if you want. A traditional subroutine Cannot be used as a function Is CALLed Doesnt use ARG or RETURN value If internal, shares variables If external, can exchange information using ISPF variables, or can use the stack (but are not modular when doing so).
68
69
ADDEMUP: PROCEDURE /* dont share vars */ Arg NUM1,NUM2 ANSWER = NUM1 + NUM2 Return ANSWER /* give answer back on RETURN */
69
70
User-written Internal Functions / Subroutines: More Examples Call ADDEMUP 1,2 Say RESULT Say NUM1 Exit /* /* /* /* invoke with CALL */ display answer */ shared and usable */ dont fall into routine */
ADDEMUP: /* share vars */ Arg NUM1,NUM2 ANSWER = NUM1 + NUM2 Return ANSWER /* give answer back on RETURN */
ADDEMUP: PROCEDURE /* dont share vars */ Arg NUM1,NUM2 ANSWER = NUM1 + NUM2 Return ANSWER /* give answer back on RETURN */
/* /* /* /*
invoke with CALL */ display answer */ shared and usable */ dont fall into routine */
ADDEMUP: /* share certain vars */ PROCEDURE EXPOSE NUM2 Arg NUM1,NUM2 ANSWER = NUM1 + NUM2 Return ANSWER /* give answer back on RETURN */
70
71
Questions
True or false: in REXX, user-written functions / subroutines may be used as either functions or subroutines. True or false: if the code is used as a function, you execute it this way: function_name(data). True or false: if the code is used as a subroutine, you execute it this way: Call function_name data and the answer comes back in RESULT.
Exercise #21
Write an exec with an internal function / subroutine to concatenate, without spaces, two data items passed to it. Invoke it as a function and as a subroutine. Check automatically within the exec to verify the calls produce the same result.
71
72
Generally, its cleaner to call a user-written function as you would any standard function. If you do code it as a call, you must quote the function name, and pass the parameters outside of the parenthesis. For example:
/* REXX */ DSN1 = SR1.CNTL; DSN2 = @TSSQ04.SR1.EXEC Call $FixDSN DSN1 /* call as subroutine */ Say The fully-qualified DSN is RESULT /* call external procedure as function */ Say Fully-qualified DSN is $FixDSN(DSN2) Exit /* REXX Fix DSN external proc Arg DSN USERID = Sysvar(SYSUID) If Left(DSN,1) = "'" Then DSN = Strip(DSN,,"'" Else DSN = USERID"."DSN Return DSN */
72
73
If function / subroutine name is NOT in quotes, search for: 1.internal (i.e. a label); 2.built-in (e.g. LENGTH); 3.external (separate program). If function / subroutine IS in quotes, search for: 1.built-in (e.g. LENGTH); 2.external (separate program).
It is advisable to do the following: Hide variables in internal functions / subroutines; If ARG uses commas, use commas in call
A final note: typically SYSEXEC is searched before SYSPROC. This is not always true, it is installation-dependent.
73
74
Exercises
You must try Exercises #22 and #25. If you choose, you may do only one of either Exercise #23 or #24.
Exercise #22
Redo the percent increase exec from Exercise #11 as an external subroutine. Name it PERCENT. Have it accept two parameters, the old number and the new number. Have it return the percent increase on the RETURN statement. Make sure both args are numeric. If either one or both are not valid, display a message and return a 0.
Exercise #23
Using your solution to #21, write your concatenate subroutine as an external function / subroutine (leave the internal one where it is). Call the external function / subroutine in such a way as to make sure you invoke the external one and not the internal one. Prove you made the right call.
Exercise #24
Create a metric conversion external subroutine called METRIC (see Exercise #16). Also write a main exec calling this function.
Exercise #25
Create an external subroutine called SQRT to compute the square root of a number passed to it. It accepts one number only. Validate the data item for being a number. If it is negative, or not numeric, display an appropriate message and return a 0. Set a loop limit of 50 (close is good enough for the cigar). Start with a guess of the number. The loop consists of this: Make new guess = (guess + (number / guess)) / 2 Make guess = new guess Return the new guess to the caller.
74
75
Heres an example:
A = 1 WEEKDAY.A = Sunday Say WEEKDAY.1 /* produces Sunday */ Say WEEKDAY.A /* produces Sunday */
You can easily vary the variable with a DO group, and step through a long list of data:
/* Assume the above assignment statements, this produces the days of the week. */ Do A = 1 to 7 Say WEEKDAY.A End
75
76
Stem Variables: A Real-world Example /* REXX to load and display the space report. Note some code is skipped to concentrate on the basics of stem variables */ RPTDATE = Date("U") /*-- Loop through the DSN list. If a report does not exist, create a new one. */ Do I = FirstDSN To SPCRPT.0 VSAMDSN = Word(SPCRPT.I,1) OUTDSN = "'DBIG."VSAMDSN".SPCHIST'" :: "ALLOC DA("OUTDSN") F(INFILE) SHR REUSE" "EXECIO * DISKR INFILE (STEM SPCOUT. FINIS" If SPCOUT.0 > 57 Then SPCOUT.0 = 57 /* The first five lines are headers. Make a blank line at Line 6 for current info. */ Do J = 1 To SPCOUT.0 If J <= 5 Then IX = J Else IX = J + 1 SPCOUT1.IX = SPCOUT.J End SPCOUT1.6 = RPTDATE Substr(SPCRPT.I,32,102) SPCOUT1.0 = SPCOUT.0 + 1 :: /* Write the records */ End
76
77
WEEKDAY. = UNKNOWN /* nothing after . */ WEEKDAY.1 = Sunday Say WEEKDAY.1 /* produces Sunday */ Say WEEKDAY.2 /* produces UNKNOWN */
If you set the default in this way, the *.0 variable also has the default value. To use *.0 to tell you the number of valid variables, you must reset it on your own.
Exercise #26
Write an exec with a loop setting NUMBER.1 through NUMBER.10 to the numbers 101 through 110. Then loop through the array, displaying the contents of NUMBER.1 through NUMBER.11, to see what happens.
77
78
DUMMY = MSG(OFF)
Of course, MSG(ON) resumes displaying these messages. You can trap most (but not all) of these messages. They are not displayed, but are still accessible if your REXX wants to use them. To trap displayed TSO messages, use the OUTTRAP function.
DUMMY = OUTTRAP(LINE.,*)
You can use any variable instead of LINE. Because this variable is a stem variable, you must include the period. The * says to capture all lines. This is the default. For the * you can substitute a number to capture that many lines.
DUMMY = OUTTRAP(LINE.,100)
captures 100 lines. Using LINE. as our stem variable, the following is true. 1. LINE.0 is the number of lines captured 2. LINE.1 is the first line captured 3. LINE.2 is the second line captured and so on. To suppress messages and not capture them either, this statement works.
DUMMY = OUTTRAP(LINE.,0)
To turn off line trapping, use this statement.
DUMMY = OUTTRAP(OFF)
78
79
DUMMY = OUTTRAP(LINE.) LISTC Say This many lines were trapped: LINE.0 Do I = 1 to LINE.0 Say Line of output was: LINE.I End DUMMY = OUTTRAP(OFF)
This example runs the CRJ command against all members of a PDS. The function STRIP removes spaces from around the member names.
/* Rexx Run CRJ against entire PDS */ Arg CRJDSN . CRJDSN = $FixDSN(CRJDSN) /* Fully qualify foo = OutTrap(MemList.) /* Trap output "LISTDS '"CRJDSN"' MEM" /* Get member list foo = OutTrap(Off) /* No more trapping /*-- Member list starts on Line 7 --*/ Do I = 7 to MemList.0 Member = Strip(MemList.I) Say "Processing job" Member Say "%CRJ '"CRJDSN"("Member")'" End Exercise #27
*/ */ */ */
Write an exec to capture the display from TSO commands. Display the lines of output one at a time. Display Please enter a command. Accept the command into a variable. Turn on OUTTRAP. Run the command, then turn off OUTTRAP. Display the message, Here comes the commands output:. Loop through the array, displaying each line of the commands output. 79
80
80
81
Terminal (end) Console Program (beginning) Stack Stack /\FIFO commands here /\LIFO commands here
LIFO commands (e.g. PUSH, EXECIO WRITE) put commands at the start of the program stack. The QUEUED() function tells you how many lines are in the stack. Data is taken from the very start of the stack by PULL, EXECIO WRITE, and several others. If the program stack is empty, data comes from the terminal input buffer. PARSE EXTERNAL takes data from the beginning of the terminal input buffer. Because that is before the program buffer starts, you can use the command to avoid getting things from the program buffer. If the terminal input buffer is empty, the keyboard unlocks and TSO waits for you to type something. If you might have something in the program stack to be saved, or as good programming practice in a new EXEC, issue the NEWSTACK command. NEWSTACK creates a new program stack and saves the old one. All subsequent commands go to this new stack until the DELSTACK command is issued. When your program ends, and all programs executing have ended, control goes back to TSO (or to the editor if the command was a macro). Anything left over in the stack is taken as a command by TSO.
81
82
Questions
What will this line of a program do: SAY QUEUED() There is nothing in either stack. Your program says PULL. What happens? Your exec does 10 PUSHes and 9 PULLs. What happens? Your exec does 9 PUSHes and 10 PULLs. What happens?
82
83
QSTACK /* queries the stack manager Stacks = RC /* Total number of stacks My_Stacks = Stacks 1 /* These are mine Say There are Stacks stacks. Do My-Stacks DELSTACK /* delete all my stacks End Push First Record Push Second Record NEWSTACK /* saves stack records, makes a new stack */ Say Please enter your name Pull NAME Say Thanks, NAME DELSTACK /* deletes current stack, restores old stack */
*/ */ */ */
Pull STACK_ELEMENT Say STACK_ELEMENT /* displays Second Record */ Pull STACK_ELEMENT Say STACK_ELEMENT /* displays First Record */
83
84
84
85
/* REXX sample to pass data to a program */ Queue Rocky Queue Bullwinkle %otherpgm /* Displays Received Rocky and Received Bullwinkle Queue Rocky Queue Bullwinkle /* Requeue lines */
*/
NEWSTACK %otherpgm /* Accepts two lines of input from user at terminal and displays them */ DELSTACK %otherpgm /* Displays Received Rocky and Received Bullwinkle */ - - - - - - - - - - - - - - - - - - - - /* REXX OTHERPGM */ Pull data_line Say Received data_line Pull data_line Say Received data_line
85
86
TSO Prompting
TSO prompting uses the same stack as PUSH, PULL, and QUEUE. Prompting in TSO defaults to ON. Prompting in an Exec defaults to OFF. You can turn prompting on if your TSO profile allows it (PROFILE PROMPT). To turn prompting on and save the previous setting:
DUMMY = PROMPT(SAVE_PROMPT)
To find out the current setting:
Exercise #28
Write a REXX to accept a dataset name from the terminal. Verify the DSN is less than 45 bytes long. Verify it exists. Place the DSN into the stack so the LISTD command can get at it. Suggestion: use QUEUE. Turn on prompting. Execute the LISTD command but omit the dataset name so TSO prompts for it. Since the DSN is in the stack, LISTD should get it from there.
86
87
0 1 2 20
successful action truncated data written if end of file a severe error was encountered
You should always close a file when finished. The FREE command does not close the file. Use the FINIS option of the EXECIO command to close files.
operation: o DISKR: read o DISKW: write o DISKRU: read for update Seq: sequence number (record number (not used on a write)). You cant go backwards. (options: o none: use the stack o STEM: use an array o FINIS: close the file
The file can be read from or written to a record at a time or all at once.
87
88
/*-- These two lines read the previous space *-- report into another stem variable. */ "ALLOC DA("OUTDSN") F(INFILE) SHR REUSE" "EXECIO * DISKR INFILE (STEM SPCOUT. FINIS"
The * tells EXECIO to retrieve all records. The (FINIS tells EXECIO to close the file when the last record has been read. This next example shows three different concepts: The stack is used to hold the one record retrieved by the EXECIO call. The RANDOM function generates a random number between the two named limits, inclusive. The PARSE PULL instruction gets the one record from storage.
/* REXX QUIP program */ NEWSTACK "ALLOC F(QUIP) DA('DBIG.EXEC(QUIPS)') SHR REU" QNUM = RANDOM(1,773) /*-- This line gets the one record named by the *-- QNUM result above. For example, if the *-- number generated was 327, the 327th record is *-- retrieved. */ "EXECIO 1 DISKR QUIP" QNUM "(FINIS" PARSE PULL QUIP SAY QUIP "FREE F(QUIP)" DELSTACK
88
89
Writing to a File
You can write to a file allocated as SHR, OLD, NEW, or MOD, but using SHR is not a good idea. Use MOD if you want to keep the data already in the file. When reading a file, we used an * to indicate all records. When writing to a file, EXECIO has no idea when youve run out of records; only you do. Therefore you always have to specify how many records to write. You can do this with a number, as we did in previous examples, or with a variable. When you do so you cannot enclose the variable within the quotes:
/* REXX Copy A File */ Arg INDSN OUTDSN INDSN = $FixDSN(INDSN) OUTDSN = $FixDSN(OUTDSN) "ALLOC F(INFILE) DA('"INDSN"') SHR REUSE" "EXECIO * DISKR INFILE (STEM INREC. FINIS" "ALLOC F(OUTFILE) DA('"OUTDSN"') NEW, LIKE(INDSN) "EXECIO * DISKW OUTFILE (STEM INREC. FINIS" FREE F(INFILE OUTFILE) Freeing Allocated Files
Dont forget to FREE your files when youre done with them. Its standard REXX TSO syntax.
FREE F(dd1)
89
90
Updating a File
Lets update a record (say, record 10) in a file. Note this uses the TSO stack; well revisit this example when we talk about the stack in the advanced course.
ALLOCATE F(INFILE) DA(TEST.DATA) OLD REUSE NEWSTACK EXECIO 1 DISKRU INFILE 10 Pull RECORD /* Get record from stack RECORD = new data /* change record Push RECORD /* Put record into stack EXECIO 1 DISKW INFILE /* write record DELSTACK /* drop the stack EXECIO 0 DISKW INFILE (FINIS FREE F(INFILE) Exercise #29
Choose a file you currently have available. Read it into an array, and then display every other line starting with Line 1.
*/ */ */ */ */
Exercise #30
Choose a file you currently have available. Read it into an array one record at a time. Count each line as you read. Keep track of the longest record length. At the end of the program, display the record count and the length of the longest record.
Exercise #31
Modify the OUTTRAP discussion example above to store the captured lines in the dataset TEMP.CAPTURE.DATA. o Use SYSDSN to see if the dataset exists. The syntax is SYSDSN(dsn_var) or SYSDSN(DSN). o If the dataset does not exist, allocate it using this command: ALLOC DA(TEMP.CAPTURE.DATA) F(CAPTURE) NEW SPACE(1 1) TRACKS LRECL(80) RECFM(F B). o OUTTRAP loads an array. Use that array to write the lines of the command display. o The WRITE command should close the file when its done writing.
90
91
References
Here is a list of references Ive found helpful. Most are on the Web. Mike Cowlishaw, the creator of REXX, wrote a book titled The REXX language: ISBN 0-13-780735-X Prentice-Hall, 1985 ISBN 0-13-780651-5 2nd edition, 1990 IBMs REXX page: http://www-306.ibm.com/software/awdtools/rexx/language/. REXX list server: http://www2.marist.edu/htbin/wlvindex?tso-rexx. REXX Language Association home page: http://www.rexxla.org. REXX FAQ page: http://www.mindspring.com/%7Edave_martin/RexxFAQ.html. The character between dave and martin is an underscore, not a blank. Mark Zeldens home page. Mr. Zelden has created a large number of useful REXX commands. The ones posted on this site are available for download. http://home.flash.net/%7Emzelden/mvsutil.html Doug Nadels home page. Mr. Nadel has been an ISPF developer at IBM for more than fifteen years. This site has several useful utilities, although not all of them are written in REXX. http://www.sillysot.com/mvs/ Lionel B. Dycks home page. Mr. Dyck has been a systems programmer since 1972. This page has a few really useful things. http://www.lbdsoftware.com/ Two pages from Neil Hancock. Mr. Hancock has been a programmer for many years, formerly for Met Office, and recently for Macro4, in the UK. The first page is a set of FAQs on REXX; the second is a REXX style guide. http://www.uberfish.freeserve.co.uk/Computers/rexxfaq.html. http://www.uberfish.freeserve.co.uk/Computers/RexxStyleGuide.html.
91
92
92
93
Accept a DSN from the user. Create a second dataset from the first, except change the third qualifier to todays date. The variable assumed here is INDSN. Parse Upper Var INDSN SDQ1 "." SDQ2 "." SDQ3 "." SDQ4 UQ3 = JDATE(J) OUTDSN = SDQ1.SDQ2"."UQ3.SDQ4 Determine if a dataset is not available. The dataset is not quoted, so a kludge is needed to pass the DSN (the POS function tells whether a quote is present). The NORECALL option tells LISTDSI not to recall a migrated dataset. IF POS("'",DSN1) = 0 THEN DSN1 = "'"DSN1"'" EXIST1 = LISTDSI(DSN1 NORECALL) IF EXIST1 > 0 THEN SAY "DATASET 1 NOT AVAILABLE" Get the dataset name of the most recent generation of a GDG. Arg GDGBASE If Left(GDGBASE,1) = "'" Then Strip(GDGBASE,,"'") foo = OutTrap(CMDDATA.) "LISTC ENT('"GDGBASE"') ALL GDG" foo = OutTrap(Off) LINE = CMDDATA.0 CURGEN = CMDDATA.LINE OFFSET = Pos("--",CURGEN) + 2 CURGEN = Strip(Substr(CURGEN,OFFSET,45)) If SYSDSN("'"CURGEN"'") <> OK Then CURGEN = "BAD" Return CURGEN
93
94
94
95
95
96
96
97
What instruction tells REXX to display something on the terminal? What does this sample program do?
SAY
97
98
1 - Say Eat; Say At; Say Joes. 2 Say Hey; Say; Man
This is incorrect. The semicolon after the second Say must be a comma. If this is run, the result is HEY on one line, a blank line, then either the TSO command MAN runs (if it exists) or an error message is displayed.
This is incorrect. The semicolon must be a colon. True. SIGNAL is the REXX equivalent
3 - Compute; C = Y - A
True or false: the EXIT statement must always be the very last line in the program. False. The EXIT statement is optional if it is the last line.
BARK Hello
No, it is passed to TSO.
98
99
*/
/* REXX Try Me Three */ GREETING = Go Away! Say Greeting Drop GREETING Say GREETING
Displays Go Away! on the terminal, and then displays GREETING on the terminal. The DROP command removes the named entry from the variable table, so its as if GREETING had never been assigned before.
99
100
cant start with a number valid cant use quotes no hyphens allowed valid, but dont do it
Say Elle
||
Woody
One.
When this prints, how many spaces will be between Elle and Woody?
Say Elle
Woody
100
101
/* REXX Runme */ Arg YOUR_NAME ADDRESS / JUNK Say Your name is YOUR_NAME Say You live at ADDRESS %RUNME JOHN 1313-1/2 DEADEND ROAD
Your name is John You live at 1313-1
101
102
Can you regain control of a runaway program by typing EXECUTIL TS? you hit ATTN or PA1 first.
Does the NOVALUE trap help enforce good programming practice? undefined variable usage versus literals. Syntax errors.
102
103
DELETE ABC.DATA
103
104
104
105
There is nothing in either stack. Your program says PULL. What happens? Keyboard unlocks, waiting for your input. Your exec does 10 PUSHes, and 9 PULLs. What happens? The last line in the stack waits for another PULL, write, or TSO command looking for input. If the exec ends before that happens, the last line in the stack is passed to TSO to be executed. Your exec does 9 PUSHes, and 10 PULLs. What happens? waiting for your input. Keyboard unlocks,
105
106
106
107
Exercise 1, page 19
Write an exec to execute the following two TSO commands: TIME SEND Sample REXX U(*) Include the comment, This is a sample REXX program for class Execute the REXX statement below, but use a continuation character and two lines: Say TIME() DATE()
/* This is a sample REXX program for class */ "TIME" "SEND 'Sample REXX ' U(*)" Say TIME(), DATE()
107
108
Exercise 2, page 21
Write an exec to display these three lines: 3 + 1 is 4 3 + 1 is 4 OBrien
Exercise 3, page 24
Write an exec to: Assign the number 10 to a variable; Assign the number 20 to a variable; In one instruction, display the total of the two.
108
109
Exercise 4, page 29
Write an exec to: Store the number 15 as a constant; Store the number 19 as a constant; Compare the numbers and find them equal.
/* Rexx FUZZ example */ A = 15 B = 19 Numeric Digits 2 Numeric Fuzz 1 If A = B Then Say "A is equal to B" Else Say "A is not equal to B"
Exercise 5, page 32
Write an exec to execute the LISTCAT ENTRY(dsn) command. Pass the DSN using ARG. Make sure it works on your own datasets and datasets not belonging to you.
109
110
Exercise 6, page 34
Write an exec to accept three pieces of information and display them in reverse order of entry. If more than three are entered, display an error message.
/* REXX rejecting additional arguments Arg VAR1 VAR2 VAR3 JUNK If JUNK = "" Then NOP Else Say "Too many args given." Say VAR3 VAR2 VAR1
*/
Exercise 7, Page 34
Write an exec to examine information passed to it. Perform the following checks: If Al is entered, display Must be a Liberal If RUSH is entered, display Gotta be a Conservative If both Al and RUSH typed in, display Look out! If neither given, display an error message
/* REXX Agenda */ Arg NAME1 NAME2 If NAME1||NAME2 = "ALRUSH", | NAME1||NAME2 = "RUSHAL" Then Say "Look out!" Else Do If NAME1 = "AL" | NAME2 = "AL" Then Say "Must be a liberal." If NAME1 = "RUSH" | NAME2 = "RUSH" Then Say "Must be a conservative." If NAME1 <> "RUSH" & NAME2 <> "RUSH", & NAME1 <> "AL" & NAME2 <> "AL" Then Say "Oh, a moderate." End
110
111
Exercise 8, Page 37
Write an exec to accept two args: the day of the week and the weather. If the day is Friday and the weather is rainy display Head for office!. If the day is Friday and the weather is not rainy display Head for golf course!.
/* REXX rainy and golf? */ Arg WEEKDAY WEATHER If WEEKDAY = "FRIDAY" Then If WEATHER = "RAINY" Then Say "Head for office." Else Say "Head for golf course!" Else NOP /* Do nothing if day not Friday */
Exercise 9, Page 39
Write an exec to ask for three, and only three, words, and display them in reversed order. /* REXX interact with user */ Say "Enter three words. Pull VAR1 VAR2 VAR3 . Say VAR3 VAR2 VAR1
/* REXX DELETE front end */ Arg DSN If DSN <> "JUNK.DATA" Then Do Say "Are you sure (enter Y/N)?" Pull ANS If ANS = "N" Then Exit /* Dont delete! */ "DELETE" DSN
111
112
/* REXX percent increase */ Say "Enter two numbers. The percent increase of" Say "the second from the first is displayed." Pull OLD NEW Say "Percent increase is" 100 * ((new - old) / old)
/* REXX input from user */ Say "What day of the week is this?" Pull WEEKDAY Say "What's the weather out? Pull WEATHER RAIN = 0 /* Default if not rainy */ If WEATHER = "RAINY" Then Do Say "How much rain (in inches)?" Pull RAIN End If WEEKDAY = "FRIDAY" & WEATHER <> "RAINY" Then Say "Head for golf course! If WEEKDAY = "SATURDAY" & RAIN < .5 Then Say "Fishing pole please!"
112
113
/* REXX error handling example Call On Error Say "Front end for LISTD. Pull DSN "LISTD" DSN Say Say "Exec terminated." Exit
*/
ERROR: Say "Command to TSO did not work on line" SIGL Say "Command was" SOURCELINE(SIGL) Say "Abend Code was" RC Say Say "The DSN may be wrong. Try again:" Pull DSN "LISTD" DSN Return
113
114
114
115
/* REXX Metric conversion */ Say "Metric conversion program." Say Say "Enter a number followed by a unit of measure. Say The unit of measure must be one of LITER, Say QUART, MILE, or KILOMETER." Pull AMT UNIT Select When UNIT = "LITER" Then Say AMT UNIT "is" AMT*1.057 "quart." When UNIT = "QUART" Then Say AMT UNIT "is" AMT*.946 "liter." When UNIT = "MILE" Then Say AMT UNIT "is" AMT*1.6 "kilometer." When UNIT = "KILOMETER" Then Say AMT UNIT "is" AMT*.625 "mile." Otherwise Say "Invalid unit entered." End
115
116
116
117
/* REXX Function Call */ Say "Enter two numbers to be subtracted. The Say result is the absolute value of the Say difference." Pull V1 V2 If DataType(V1) <> "NUM" | DataType(V2) <> "NUM" Then Do Say "At least one value not numeric." Exit End Say "Difference is" ABS(V1 - V2)
117
118
/* REXX subroutine call: internal */ Say "Enter two data items to concatenate together. Say "Separate the items by a space." Pull VAR1 VAR2 Call CONC VAR1,VAR2 SUBRES = RESULT SUBFUN = CONC(VAR1,VAR2) NOSUBR = VAR1||VAR2 /* Call as subroutine */ /* Call as function */ /* Concat compare */
Say "Called as subroutine: " SUBRES Say "Called as function: " SUBFUN Say "'Normal' concatenation: " NOSUBR If SUBRES == SUBFUN /* Exact equality */ Then Say "Function and subroutine calls match Else Say "Function and subroutine do not match Exit /*-----------------------------------------* * CONCatenate any two variables into one. * *-----------------------------------------*/ CONC: Arg V1,V2 ANS = VAR1||VAR2 RETURN ANS
118
119
119
120
/* REXX subroutine call: internal */ Arg V1,V2 ANS = V1||V2 Say "Entered External Subroutine! RETURN ANS /* Go back to to caller */
/* REXX caller: internal vs external */ Say "Enter two data items to concatenate. Say "Separate the items by a space." Pull VAR1 VAR2 Call "EX23" VAR1,VAR2 Exit /*--------------------------------------------* * This is the subroutine as an internal * * call. There is a display in the external * * call, none in this one. If the external * * one is called, you should see the display. * *--------------------------------------------*/ EX23: Arg V1,V2 ANS = V1||V2 RETURN ANS /* Return the answer */
120
121
/* REXX Metric conversion Arg AMT,UNIT Select When UNIT = "LITER" When UNIT = "QUART" When UNIT = "MILE" When UNIT = "KILOMETER" Otherwise ANS = 0 End Return ANS
returns "0" if invalid */ Then Then Then Then ANS ANS ANS ANS = = = = AMT*1.057 AMT*.946 AMT*1.6 AMT*.625
/* REXX Metric conversion caller */ Say "Metric conversion program. Enter a number Say "followed by a unit of measure. Note the unit" Say "of measure must be one of LITER, QUART, MILE, Say or KILOMETER." Pull AMOUNT UNIT Call "EX24" AMOUNT,UNIT Select When UNIT = "LITER" Then Say AMOUNT UNIT "is" When UNIT = "QUART" Then Say AMOUNT UNIT "is" When UNIT = "MILE" Then Say AMOUNT UNIT "is" When UNIT = "KILOMETER" Then Say AMOUNT UNIT "is" Otherwise Say "Invalid unit End
121
122
*/
/* Validate if numeric and greater than 0 */ If DataType(BASE) <> "NUM" Then Do Say "Variable passed is not a valid number. Return 0 End If BASE <= 0 Then Do Say "Variable is 0 or negative. Return 0 End /* Now determine square root. 50 times close enough */ NEWNUM = BASE / 2 /* First guess is 1/2 number */ Do 50 If NEWNUM * NEWNUM = BASE then leave NEWNUM = (NEWNUM + (BASE / NEWNUM)) / 2 End Return NEWNUM /* REXX square root program CALLER */ Say "Enter a number to calculate the square root." Pull NUM Say "Square root of NUM is EX25(NUM) .
122
123
/* REXX using stems */ Do I = 1 to 10 NUMBER.I = 100 + I End Do I = 1 to 11 Say "Number" I "is" NUMBER.I End
/*Rexx -- capture TSO command Say "Enter a TSO command:" Pull CMD DUMMY = OutTrap(Display_Line.) Address TSO CMD DUMMY = OutTrap(Off) Say "Here comes the output: Do I = 1 to Display_Line.0 Say Display_Line.I End
123
124
/* REXX use the stack to pass a DSN to LISTD. */ Say "Enter dataset name to pass to LISTD." Pull DSN If Length(DSN) > 44 Then Do Say "DSN" DSN "longer than 44 bytes." Exit End If SYSDSN(DSN) <> "OK" Then Do Say DSN "does not exist." Exit End Queue DSN DUMMY = Prompt("ON") "LISTD"
124
125
125
126
/* REXX read a file a record at a time */ ALLOCATE F(INFILE) DA(your.dsn) SHR REUSE NEWSTACK LineNum = 0 LLine = 0 EOF = NO Call READIT MAINLINE: Do I = 1 While EOF = NO LineNum = LineNum + 1 Pull RECORD LineLen = Length(RECORD) If LineLen > LLine Then LLine = LineLen Call READIT End Say Number of lines read: LineNum Say Length of Longest Record: LLine DELSTACK FREE F(INFILE) Exit READIT: EXECIO 1 DISKR INFILE If RC <> 0 Then Do EOF = YES EXECIO 0 DISKR INFILE (FINIS End Return
126
127
The write command should close the file when its done writing.
/* REXX Capture output from command in dataset */ Say Enter TSO command: Pull CMD DUMMY = OutTrap(Display_Line.) Address TSO CMD DUMMY = OutTrap(Off) If SYSDSN(TEMP.CAPTURE.DATA) = OK Then ALLOC F(CAPTURE) DA(TEMP.CAPTURE.DATA) OLD REUSE Else ALLOC F(CAPTURE) DA(TEMP.CAPTURE.DATA) NEW REUSE SPACE(1 1) TRACKS LRECL(80) RECFM(F B) "EXECIO" Display_Line.0 "DISKW CAPTURE (STEM Display_Line. FINIS Address ISPEXEC BROWSE DATASET(TEMP.CAPTURE.DATA)
127
The ARG instruction receives data from a calling program. It is a short form of PARSE UPPER ARG. In a main program it receives data typed on the command line; in a function or subroutine it receives data passed to it on the call. The data may be received in one or more variables separated by a delimiter such as a space or comma. Fields separated by spaces are considered words; commas are normally used in function calls. Use a period (.) to drop variables. ARG FIELD1 FIELD2 FIELD3 places the first word (all characters up to the first blank) in FIELD1, the second word in FIELD2, and all remaining characters (spaces and all) in FIELD3. ARG FIELDS places all data passed into the variable FIELDS. ARG FIELD1 FIELD2 . places the first word in FIELD1, the second word in FIELD2, and ignores everything after the second word. ARG FIELD1,FIELD2 places all data before the first comma into FIELD1 and the remaining data into FIELD2. The CALL instruction invokes a subroutine, whether external or internal. The called routine should end with a RETURN instructor. CALL can also turn on or off an error trap. CALL subroutine parameters passes parameters to the subroutine, which picks them up via the ARG instruction. The subroutine passes the result, if any, in the variable RESULT. Example: CALL LENGTH ABCD SAY RESULT
/* displays a 4 */
CALL ON condition-name sets up an error trap (see SIGNAL). If the error trap is entered, a RETURN at the end of the trap sends control back to the instruction after the failed instruction. Example: CALL ON ERROR /* sends control to the ERROR trap */
CONWAIT is a CMS-only instruction. It waits until all output directed to the terminal has been displayed. Often used with DESBUF to ensure no terminal output is lost while clearing the terminal output buffer. Example: PUSH CART CONWAIT DESBUF /* CART is lost */ DESBUF is a CMS-only instruction. It clears the stack and both the input and output terminal buffers. Often used with CONWAIT to ensure no terminal output is lost while clearing the buffers. Example: PUSH CART CONWAIT DESBUF /* CART is lost */ The DO instruction starts a group of instructions to be performed repeatedly. The number of times the instruction group repeats is controlled by a variable or a REXX keyword set. Some examples: DO I = 1 TO 10 SAY I END DO I = 10 TO 1 BY -1 SAY I END /* Increment a variable */
/* Decrement a variable */
DO FOREVER /* Loop forever, get out with LEAVE */ IF TIME() > 16:00:00 THEN LEAVE END DO UNTIL TIME() > 16:00:00 SAY WORK END DO WHILE TIME() < 16:00:00 SAY WORK END DO 10; SAY WORK; END /* Until test true */
/* As long as true */
DROP undefines a variable. REXX takes the string as an upper case literal. Example: GREETING = HI! SAY GREETING /* displays HI! on the screen */ DROP GREETING SAY GREETING /* displays GREETING on the screen */ END ends a DO or SELECT structure. If on a counting loop, END can name the counting variable to ensure the right loop is ending. Example: DO I = 1 TO 10 SAY I END I /* we know its ending the DO I loop */ The EXECIO TSO/CMS instruction handles dataset I/O for reading, writing, and updating datasets in a REXX exec. In TSO you must ALLOCATE the dataset before you can run EXECIO. CMS examples: note filename, filetype, and filemode stand for the actual file being read or written. EXECIO * CARD reads from reader into stack EXECIO * CARD (STEM RECD. reads from the reader into the variables RECD.1 through RECD.n where n is the number of cards read. EXECIO sets RECD.0 to the number of cards read. EXECIO RECD.0 PRINT writes all records from RECD. to the printer. EXECIO QUEUED() PUNCH writes all records from the stack to punch. EXECIO * DISKR filename filetype filemode reads from the named file into the stack EXECIO * DISKR filename filetype filemode (STEM RECD. reads from the named file into the stem variable RECD. EXECIO QUEUED() DISKW filename filetype filemode writes all records from the stack to the named file.
EXECIO CMS examples continued. EXECIO RECD.0 DISKW filename filetype filemode (STEM RECD. writes the entire array RECD. to the named file. EXECIO 1 DISKRU filename filetype filemode gets one record from the file and holds it for rewriting. EXECIO 1 DISKRU filename filetype filemode (VAR REC1 gets one record from the file and holds it in the variable REC1 for rewriting. EXECIO 1 CP (STRING QUERY READER ALL) passes the command QUERY READER ALL to CP and receives the reply in the stack. FINIS filename filetype filemode closes the file. TSO examples: note ddname stands for the DDname of the dataset being read or written. EXECIO * DISKR ddname (FINIS reads from the dataset into the stack and closes the dataset. EXECIO * DISKR ddname (STEM RECD. FINIS reads from the dataset into the array RECD. and closes the dataset. EXECIO QUEUED() DISKW ddname (FINIS writes all records from the stack to a dataset and closes it. EXECIO RECD.0 DISKW ddname (STEM RECD. FINIS writes all records from the array RECD. to a dataset and closes it. EXECIO 1 DISKRU ddname gets one record from the file and holds it for rewriting. EXECIO 1 DISKRU ddname (VAR REC1 gets one record from the file and holds it in the variable REC1 for rewriting.
The EXECUTIL instruction is valid in TSO only. It may be executed inside an exec or as a native TSO command. It controls the execution of a REXX exec. Some examples: EXECUTIL TS turns on interactive debugging with TRACE R. EXECUTIL TE turns off interactive debugging. EXECUTIL HT stops display of all SAYs, even in other execs. EXECUTIL RT resumes display of all SAYs. EXECUTIL HI stops program execution. EXECUTIL SEARCHDD(YES) usually executed before the first REXX exec in a TSO session. It causes TSO to search for REXX execs in the DDname SYSEXEC (the default is SYSPROC). Not usually found inside REXX execs. The EXIT instruction ends the REXX program and returns control to the calling program or environment. May pass back a return code (numeric only) by coding it after the instruction (EXIT 8 passes a return code of 8). The return code can be checked as follows: TSO: use the WHEN TSO command to check. CMS: return code is displayed on the terminal. REXX exec: return code is found in the variable RC. CLIST: the return code is found in the variables &LASTCC and &MAXCC.
The EXPOSE instruction is used with the PROCEDURE instruction to allow the named variables to be shared with the main program. In effect, EXPOSE makes the named variables global. This instruction is usually found right after the PROCEDURE statement; for example: SUBPGM: PROCEDURE EXPOSE VAR1 shares VAR1 with the main program; all other variables in the procedure SUBPGM are protected and cannot be seen or modified by the main program.
The HI instruction stops execution of the program (HI is Halt Immediate). In TSO it may only be executed after an ATTN interrupt. In CMS, it may be executed only when the screen displays MORE in the lower right. The HT instruction stops display to the terminal (HT is Halt Terminal). In TSO it may only be executed after an ATTN interrupt. In CMS, it may be executed only when the screen displays MORE in the lower right. See the RT command. The IF instruction controls conditional execution of one or more instructions. If the expression is true, the instrruction on the THEN keyword is processed. If the expression is false, either nothing happens (no ELSE) or the instruction on the ELSE keyword is executed. The format of the IF instruction is: IF expression THEN instruction ELSE instruction The expression may contain one of these comparison operators. Numbers are compared numerically, characters by the collating sequence. See also the description under equal and strictly equal. = Equal. Numbers are equal numerically, e.g. 001.0 equals 1. Characters are considered equal ignoring leading or trailing spaces, e.g. DEB is equal to DEB. Case is significant, so DEB does not equal Deb. Not equal. The opposite of =. Other ways of writing not equal are ^=, \=, and =. Greater than. Greater than or equal. Not greater than. The opposite of >. Other ways of writing not greater than are ^= and \=. Less than. Less than or equal. Not less than. The opposite of <. Other ways of writing not less than are ^= and \=.
IF expressions continued. == Equal in every way, strictly equal. This is a bit comparison rather than a value comparison.
\== Not strictly equal. Also ==. >> Strictly greater than. This is a bit comparison.
>>= Strictly greater than or equal to. This is a bit comparison. << Strictly less than. This is a bit comparison.
<<= Strictly less than or equal. This is a bit comparison. >> Strictly not greater than. This is a bit comparison. << Strictly not less than. This is a bit comparison. The expression may also contain one or more of these logical connectors. & | && AND. Both conditions must be true. OR. One or both conditions must be true. Exclusive OR. Only one, but not both, conditions must be true.
Examples: IF A = 1 THEN SAY A IS EQUAL TO 1 ELSE SAY A IS NOT EQUAL TO 1 IF A = 1 THEN DO SAY A IS EQUAL TO 1 SAY ISNT IT? END ELSE SAY A IS NOT EQUAL TO 1
IF examples continued. IF A = 1 & B = 1 THEN SAY A and B ARE BOTH EQUAL TO 1 ELSE SAY ONE OF A OR B IS NOT EQUAL TO 1 IF A == DATE THEN SAY TRULY A DATE ELSE SAY MAYBE A DATE, BUT NOT EXACTLY IF A = MEAT THEN SAY I CAN EAT THAT ELSE DO SAY SORRY, IM A VEGETARIAN EXIT END IF A <= 3 THEN SELECT WHEN A = 1 THEN SAY ITS ON! WHEN A = 3 THEN SAY ITS OFF! OTHERWISE SAY ITS NOT ON OR OFF. END ELSE IF A = 4 THEN SAY SWITCH IS IN MIDDLE. ELSE SAY INVALID VALUE FOR A. TRUE = 1 IF TRUE THEN SAY ITS TRUE! ELSE SAY DONT LIE TO ME! The INTERPRET instruction causes REXX to look at data as if it is seeing it for the first time. The data may be a REXX instruction or a command meant for the command processor. Two examples: INTERPRET SAY HI! PART1 = S PART2 = AY HI PART3 = ! INTERPRET PART1||PART2||PART3
The ITERATE instruction sends control to the DO of a DO-END loop. It skips the instructions between it and the END. In a nested loop, ITERATE works only in its loop. If ITERATE names a loops variable, REXX iterates within that loop. Three examples: DO I = 1 TO 20 IF I = 13 THEN ITERATE SAY I END /* SKIP #13 */
DO 20 /* Skips #13 in the inner loop only */ DO I = 1 TO 20 IF I = 13 THEN ITERATE SAY I END END DO HR = 1 TO 12 DO MM = 1 TO 60 IF MM = 60 THEN ITERATE HR SAY HR:MM END END
/* next hour */
The LEAVE instruction sends control to the instruction after the END of a DO-END loop. LEAVE ends the loop its in. In a nested loop, LEAVE works only in its oen loop. If LEAVE names a loops variable, REXX iterates within that loop. Three examples: DO I = 1 TO 20 IF I = 13 THEN LEAVE SAY I END /* PRINT 1 12 ONLY */
DO 20 /* The process is still done 20 times */ DO I = 1 TO 20 IF I = 13 THEN LEAVE /* PRINT 1 12 ONLY */ SAY I END END DO HR = 1 TO 12 DO MM = 1 TO 60 IF MM = 60 THEN LEAVE HR SAY HR:MM END END
/* next hour */
The MAKEBUF instruction creates a new buffer. This buffer can be used like a stack, but does not isolate the current stack. The buffers number is returned in the variable RC. Drop buffers created with DROPBUF. When you delete the buffer, all its data is lost. Here are two examples. MAKEBUF BUFNO = RC SAY QUEUED() PUSH CART SAY QUEUED() DROPBUF BUFNO SAY QUEUED() SAY ENTER NAME PULL NAME SAY THANKS, NAME. PUSH CART SAY QUEUED() MAKEBUF BUFNO = RC SAY QUEUED() SAY ENTER NAME PULL NAME SAY QUEUED() SAY THANKS, NAME. DROPBUF BUFNO /* /* /* /* /* /* /* save buffer number */ displays 1 */ place CART in stack */ displays 1 */ release MAKEBUF buffer */ displays 0 (CART went away */ assume Arthur */
/* NAME = Arthur */ /* place CART in stack */ /* displays 1 */ /* save buffer number */ /* displays 1 */ /* displays 0 */ /* NAME = CART */ /* release MAKEBUF buffer */
The NEWSTACK instruction creates a new program stack. Anything in the old stack is preserved, but unavailable. Keep track of any new stacks you create. Drop user-created stacks with the DELSTACK command. When the last user-defined stack is gone, the original program stack is again available. Here are two examples. PUSH CART SAY QUEUED() /* displays 1 */ NEWSTACK /* get a new stack */ SAY QUEUED() /* displays 0 */ SAY ENTER NAME /* assume Arthur */ PULL NAME SAY QUEUED() /* displays 0 */ SAY THANKS, NAME. /* NAME = Arthur */ DELSTACK /* return to the old stack */ SAY QUEUED() /* displays 1 */ SAY ENTER VEHICLE /* assume TAXI */ PULL VEHICLE SAY VEHICLE WAS VEHICLE. /* displays CART */ NEWSTACK PUSH CART /* place CART in stack */ SAY QUEUED() /* displays 1 */ DELSTACK /* Removes stack with CART */ SAY QUEUED() /* displays 0 */ SAY ENTER NAME /* assume Arthur */ PULL NAME SAY QUEUED() /* displays 0 */ SAY THANKS, NAME. /* NAME = Arthur */ SAY QUEUED() /* displays 1 */ SAY ENTER VEHICLE /* assume TAXI */ PULL VEHICLE SAY VEHICLE WAS VEHICLE. /* displays TAXI */
The NOP instruction tells REXX to do nothing. Heres an example. IF A = B THEN NOP ELSE SAY A IS NOT EQUAL TO B. The NUMERIC instruction sets the way REXX deals with numbers. It has three forms, explained below with examples. NUMERIC DIGITS number sets the precision of arithmetic operations. The system default is 9. While there is no limit to precision, high precision has high overhead. If the number of digits exceeds the precision, the least significant digit is rounded. NUMERIC FORM SCIENTIFIC or ENGINEERING sets the way numbers are shown in exponential notation. NUMERIC FORM SAY 1.0001 * NUMERIC FORM SAY 1.0001 * SCIENTIFIC 10000000000000 ENGINEERING 10000000000000 /* The default */ /* displays 1.00010000E+9 */ /* displays 100.010000E+7 */
NUMERIC FUZZ number controls the number of low-order digits in numeric comparisons. This allows approximation instead of insisting on exact equality. NUMERIC FUZZ 1 /* Ignore least significant digit */ IF 987654321 = 987654320 THEN SAY SURPRISE! ELSE SAY THIS WONT HAPPEN. The OTHERWISE instruction notes the default alternative in a SELECT structure. This path is taken if none of the SELECT conditions are true. OTHERWISE is optional; however, an END is required at the end of the SELECT whether there is an OTHERWISE or not. SELECT WHEN S = M THEN SAY HI, MISTER! WHEN S = F THEN SAY HELLO, MISS! OTHERWISE SAY GREETINGS! END
The PARSE instruction does character string functions. The basic syntax for PARSE is: PARSE (UPPER) origin template The UPPER is optional. If used, it converts the characters to upper case. If it is not used, the characters remain in the case they started in. PARSE takes the data from the origin and processes it using the template. The net result is that all the variables in the template are set or changed in some way. The template is just a list of variables. Possible orgins are: ARG the command line.
EXTERNAL the terminal, without passing through the stack. PULL SOURCE VALUE VAR VERSION the stack. internal settings from the environment and program. a literal, function result, or variable. a variable. internal system information about the version of REXX.
On this and the next two pages are several examples. Normal parsing is done based on spaces. /* REXX STOOGE */ PARSE UPPER ARG VAR1 VAR2 VAR3 SAY VAR1 SAY VAR2 SAY VAR3 > STOOGE MOE LARRY CURLEY MOE LARRY CURLEY
PARSE examples continued. Using a literal string delimiter. Data is first split at the delimiting character(s). Each side of the delimiter is split by spaces or other delimiters. The delimiter is not considered part of the string. /* REXX STOOGE */ PARSE UPPER ARG VAR1 VAR2 ! VAR3 SAY VAR1 VAR2 SAY VAR3 > STOOGE HEY MOE! HEY MOE HELLO! Using column delimiters. Data is split at the columns given. The number to the left of a variable is the starting column; the number to the right of a variable is the ending column, minus one. /* REXX ALPA BETTY */ PARSE UPPER ARG 1 VAR1 4 VAR2 8 VAR3 11 SAY VAR1 SAY VAR2 SAY VAR3 > ALPHA ABCDEFGHIJKLMNOPQRSTUVWXYZ ABC DEFG HIJ /* REXX ALPA BETTY */ PARSE UPPER ARG 1 VAR1 4 6 VAR2 8 5 VAR3 11 SAY VAR1 SAY VAR2 SAY VAR3 > ALPHA ABCDEFGHIJKLMNOPQRSTUVWXYZ ABC FG EFGHIJK HELLO!
Using a value. PARSE VALUE TWO WORDS ONLY VAR1 VAR2 . SAY VAR1 SAY VAR2 TWO WORDS Using a variable. VARSTRING = HELLO ALL YOU PEOPLE PARSE VAR VARSTRING VAR1 VAR2 VAR3 SAY VAR1 SAY VAR2 SAY VAR3 HELLO ALL YOU PEOPLE The PROCEDURE instruction is used in a subroutine or internal function to protect the variables from the main programs effects. Example: SUB1: PROCEDURE The PULL instruction takes a line from the program stack or, if empty, from the terminal input buffer. Short form of PARSE UPPER PULL, see PARSE for more information. The PUSH instruction puts a line into the program stack last in, first out (LIFO) (see the QUEUE instruction). For example, PUSH HAS FLEAS VAR1 = MY DOG PUSH VAR1 PULL LINE SAY LINE PULL LINE SAY LINE The resulting output is MY DOG HAS FLEAS.
The QBUF instruction returns the number of buffers created by the MAKEBUF instruction. The number of buffers is returned in the variable RC. For example, QBUF SAY RC MAKEBUF QBUF SAY RC DROPBUF QBUF SAY RC /* returns 0 */ /* returns 1 */ /* returns 0 */
The QELEM instruction returns the number of elements or lines are available in the buffer created by MAKEBUF. The number of buffers is returned in the variable RC. For example, MAKEBUF PUSH CART PUSH CAR QELEM SAY RC /* returns 2 */ DROPBUF QELEM SAY RC /* returns 0 */ The QSTACK instruction is available in TSO only. It returns the number of stacks created by the NEWSTACK instruction, plus one. The number of stacks is returned in the variable RC. To drop all the new stacks, use RC 1 to know how many times to run the DELSTACK command. For example, QSTACK HOW_MANY = RC - 1 DO HOW_MANY DELSTACK END
The QUEUE instruction puts a line in the program stack. Data is put into the stack first in, first out (FIFO) (see the PUSH instruction). For example, PUSH HAS FLEAS VAR1 = MY DOG PUSH VAR1 PULL LINE SAY LINE PULL LINE SAY LINE The resulting output is MY DOG HAS FLEAS. The RETURN instruction sends control back from a subroutine or internal function to the instruction just after the call. Except in an error trap, can pass back a single string or variable to the caller. For example: SUBR: ARG NUM1,NUM2 TOTAL = NUM1 + NUM2 RETURN TOTAL Returns the sum of NUM1 and NUM2 back to the main program. The RT instruction resumes display to the terminal (RT is Resume Terminal). This is the opposite of HT. In TSO it may only be executed after an ATTN interrupt. In CMS, it may be executed only when the screen displays MORE in the lower right. The SAY instruction displays a line on the terminal. The line may be either a variable, a literal, a function call, or any combination. Examples: SAY A = SAY SAY SAY Aaah! /* 1 A /* TIME() /* A is A, displays Aaah! */ displays 1 */ displays result of the TIME function */ time is TIME().
The SELECT instruction is REXXs CASE structure. Provides a selection of one of many alternatives. An END is required at the end of the SELECT. OTHERWISE provides an optional default answer. Often OTHERWISE is some sort of DO group to correct for the missing cases. Example: SELECT WHEN DAY = 1 THEN WHEN DAY = 2 THEN WHEN DAY = 3 THEN WHEN DAY = 4 THEN WHEN DAY = 5 THEN WHEN DAY = 6 THEN WHEN DAY = 7 THEN OTHERWISE SAY NO END SAY SUNDAY SAY MONDAY SAY TUESDAY SAY WEDNESDAY SAY THURSDAY SAY FRIDAY SAY SATURDAY SUCH DAY OF THE WEEK!
The SIGNAL instruction turns on or off a condition trap named by a label. The trap can interrupt a non-normal condition wherever it occurs after the SIGNAL. The code for the error trap is found after the end of the main program. Examples: SIGNAL ON SYNTAX SIGNAL ON ERROR SIGNAL ON FAILURE SIGNAL ON NOVALUE SIGNAL ON HALT :: code EXIT SYNTAX: SAY SYNTAX ERROR! EXIT NOVALUE: SAY UNINITIALIZED VARIABLE ON SOURCELINE(SIGL) RETURN SIGNAL can also be used as a label for a GOTO operation. For example, SIGNAL DONE :: code DONE: A = A + 1 /* /* /* /* /* syntax error */ command in error */ command doesnt exist */ uninitialized variable */ attention interrupt */
The SUBCOM instruction asks TSO or CMS if a particular environment is available, and returns the answer in RC. RC is 0 if the environment is available, 1 if not. Examples: SUBCOM SAY RC SUBCOM SAY RC SUBCOM SAY RC SUBCOM SAY RC SUBCOM SAY RC TSO /* ISPEXEC /* ISPEXEC /* XEDIT /* USA /* displays 0 under TSO */ displays 1 under TSO */ displays 0 in ISPF */ displays 0 if in XEDIT */ displays 1 */
The TE instruction is valid for TSO only. It turns interactive debugging off, and may be run only after an attention interrupt. The TS instruction turns interactive debugging on. In TSO it may only be executed after an ATTN interrupt. In CMS, it may be executed only when the screen displays MORE in the lower right. The UPPER instruction converts the alphabetic contents of a variable to upper case. Example: VAR1 = this, 2, is lower case. UPPER VAR1 SAY VAR1 /* produces THIS, 2, IS LOWER CASE. */
The TRACE instruction controls tracing and interactive debugging. The TRACE instruction has the following operands, listed in order from the least things traced to the most things traced. TRACE ! TRACE O TRACE N TRACE F TRACE E TRACE !C TRACE C TRACE L TRACE A TRACE S TRACE !R Nothing traced, dont execute any commands. Nothing traced. Normal, TSO/CMS commands failing or erroring out are traced. Failure, non-existent or abending TSO/CMS commands Error, non-working TSO/CMS commands Trace commands but dont execute them Commands, TSO/CMS commands Labels only All (labels, commands, REXX verbs) Scan labels, commands, and REXX verbs Results for labels, commands, REXX verbs, or any time a variable is changed, but dont execute any commands Results for labels, commands, REXX verbs, or any time a variable is changed Results for labels, commands, REXX verbs, or any time a variable is changed with interactive debug Intermediate, labels, commands, REXX verbs, or any time a variable is changed, showing intermediate results (e. g. C = (4+3) * 2), and dont execute commands. Intermediate, labels, commands, REXX verbs, or any time a variable is changed, showing intermediate results (e. g. C = (4+3) * 2)
TRACE I
REXX functions
The REXX functions listed here are supported under both TSO and CMS unless otherwise noted. Functions may be used in one of two ways: Letting REXX substitute the value for the function. For example, SAY LENGTH(ABCD) becomes SAY 4, which displays 4 on the terminal. SAVE_LEN = LENGTH(ABCD) /* assignment */
SAY NAME HAS LENGTH(NAME) LETTERS. SAY DOUBLE THE NAMES LENGTH IS 2 * LENGTH(NAME) NOTES: o There must not be a space between the function name and the parentheses. o The result of the function is not available in the variable RESULT. o Separate parameters with commas, not spaces. For example, LEFT(ABCD,3). Using the special variable RESULT to get the value for the function. For example, CALL LENGTH ABCD SAY RESULT CALL LENGTH ABCD SAVE_LEN = RESULT /* displays 4 */ /* assignment */
CALL LENGTH NAME SAY NAME CONTAINS RESULT CHARACTERS. CALL LENGTH NAME SAY DOUBLE THE NAMES LENGTH IS 2 * RESULT NOTES: o You must do a CALL for the answer to be in RESULT. o Separate parameters with commas, not spaces. For example, LEFT ABCD,3. o Parentheses are not used.
ABBREV(word,abbrev,length). Tells whether abbrev is a valid abbreviation of word, considering length characters. If the length is omitted, all characters are checked. The function returns a 1 if it is a valid abbreviation, 0 if it is not. Examples: SAY SAY SAY SAY ABBREV(ALLOCATE,AL,2) ABBREV(ALLOCATE,AL) ABBREV(ALLOCATE,ALK,2) ABBREV(ALLOCATE,ALK) /* /* /* /* returns returns returns returns 1 1 0 0 */ */ */ */
ABS(number). Returns the absolute value (i.e. drops the sign) of a number. Formats the result using the current NUMERIC setting. For example: SAY ABS(-12.3) /* displays 12.3 */
ADDRESS(). Returns the name of the current environment as follows: TSO: returns TSO, MVS, ISPEXEC, or ISREDIT CMS: returns CMS, COMMAND, XEDIT Example: SAY ADDRESS() /* might display TSO */
ARG(number,operand). The ARG function has four forms, detailed on this page. ARG() returns the number of argument strings passed (commas delimit argument strings). You can pass several to a subroutine or function, but only one to a main program. Example: CALL SUBR CINDY,DEB LORI EXIT SUBR: SAY ARG() /* displays 2 */ ARG(number) returns the argument string of the number passed. Example: CALL SUBR CINDY,DEB LORI EXIT SUBR: SAY ARG(2) /* displays DEB LORI */ ARG(number,EXISTS) returns a 1 if the argument numbered number exists, a 0 if it does not. EXISTS may be abbreviated E. CALL SUBR CINDY,DEB LORI EXIT SUBR: SAY ARG(2,EXISTS) /* displays 1 */ SAY ARG(5,E) /* displays 0 */ ARG(number,OMITTED) returns a 1 if the argument numbered number does not exist, a 0 if it does. OMITTED may be abbreviated O. CALL SUBR CINDY,DEB LORI EXIT SUBR: SAY ARG(2,OMITTED) /* displays 0 (is there) */ SAY ARG(5,O) /* displays 1 (not there */
BITAND(string1,string2,pad). BITAND logically ANDs string1 and string2, with pad used to fill the shorter string to the right. Each bit in string1 is compared to the corresponding bit in string2. Each bit in the result is set to 1 if the matching bits in both string1 and string2 are a 1. If both bits dont match, the corresponding bit in the result is set to 0. Example: SAY BITAND(01X,0FX) /* displays 01X */
BITOR(string1,string2,pad). BITOR logically ORs string1 and string2, with pad used to fill the shorter string to the right. Each bit in string1 is compared to the corresponding bit in string2. Each bit in the result is set to 1 if the matching bit in either string is a 1. If neither bit in the strings are 1, the corresponding bit in the result is set to 0. Examples: SAY BITOR(01X,0FX) SAY BITOR(01X,0EX) /* displays 0FX */ /* displays 0FX */
BITXOR(string1,string2,pad). BITXOR logically ORs string1 and string2, with pad used to fill the shorter string to the right. Each bit in string1 is compared to the corresponding bit in string2. Each bit in the result is set to 1 if only one, not both, of the matching bits in both string1 and string2 are a 1. If both bits arent 1, or both bits are 1, the corresponding bit in the result is set to 0. Examples: SAY BITOR(01X,0FX) SAY BITOR(01X,0EX) /* displays 0EX */ /* displays 0FX */
CENTER(string,length,pad). Centers string within a larger string of length. Pad, if present, is used to pad the string to the left and right; the default is spaces. Examples: CENTER(CENTER,10) CENTER(CENTER,10,-) /* returns CENTER */ /* returns --CENTER-- */
COMPARE(string1,string2,pad). Compares string1 to string2. If pad is supplied, it is used to fill the shorter string; the default is spaces. If both strings are equal COMPARE returns a 0. If the strings are not equal, the character position of the discompare is returned. Examples: COMPARE(APPLES,APPLES) COMPARE(APPLES,APPLESAUCE) /* returns 0 */ /* returns 1 */
CONDITION(type). Normally used in a condition trap, this function gives information about the condition found. Valid types are: C gives the name of the condition (ERROR, FAILURE, NOVALUE, HALT, SYNTAX). D when possible, gives the string causing the error. I gives the instruction sending to the trap (SIGNAL or CALL). S gives the current status of the condition (ON, OFF, or DELAY). DELAY means the condition is currently trapped, and further trapping is disabled to prevent recursive calling of error trap.
Examples: SIGNAL ON ERROR LISTCAT NOHLQ EXIT ERROR: SAY COMMAND FAILED! SAY CONDITION(C) /* displays ERROR */ SAY CONDITION(D) /* displays LISTCAT NOHLQ */ SAY CONDITION(I) /* displays SIGNAL */ EXIT COPIES(string,how-many). Returns how-many copies of string, one after another. Examples: COPIES(MORE,3) COPIES(LESS,0) Copies( ,80) /* returns MOREMOREMORE */ /* returns nothing (no copies) */ /* returns a line of 80 spaces */
C2D(string). Converts string to its binary form, then to a decimal number. Examples: SAY C2D(B) SAY C2D(b) SAY C2D(10X) /* displays 194 */ /* displays 130 */ /* displays 16 */
C2X(string). Converts string to its hexadecimal form. Examples: SAY SAY SAY SAY C2X(B) C2X(b) C2X(16) C2X(16) /* /* /* /* displays C2 */ displays 82 */ displays F1F6 */ displays F1F6 */
DATATYPE(string) Returns NUM if string is a number, otherwise it returns CHAR. SAY DATATYPE(1234) SAY DATATYPE(Z234) DATATYPE(string,type) Returns 1 if string has the same type as type, otherwise it returns 0. Note you may need to strip extra spaces to get this to work properly; for example, SAY DATATYPE(SPACE(ABCD,0),U) Valid types: A alphanumeric (A Z, a z, 0 9) B binary digits 1 and 0 D double-byte characters L lower-case characters M mixed-case characters N valid number S valid REXX symbol U upper-case letters W whole number X hexadecimal number (0 9, A F) Examples: SAY DATATYPE(1234,N) /* returns SAY DATATYPE(Z234,N) /* returns SAY DATATYPE(AbcD,M) /* returns SAY DATATYPE(Z234,A) /* returns SAY DATATYPE(ABCD,X) /* returns IF DATATYPE(VAR1,N) THEN SAY VAR1 IS A NUMBER. ELSE SAY VAR1 IS NOT A NUMBER. 1 0 1 1 1 */ */ */ */ */ /* returns 1 */ /* returns NUM */ /* returns CHAR */
DATE(). Returns the current date in the format 12 JULY 2002. DATE(type). Returns the current date in the format indicated by type. Valid types: B base date, number of days since January 1, year 1. C century, the number of days in this century. D days, the number of days so far this year. E Eurpean date, format dd/mm/yyyy. J Julian date, format yyyyddd. M the name of the current month. O ordered date, sortable, format yyyy/mm/dd. S sortable date, yyyymmdd. U USA format, mm/dd/yyyy. W the name of the current weekday. Examples (for June 17, 2008): SAY SAY SAY SAY SAY SAY SAY SAY SAY SAY DATE(B) DATE(C) DATE(D) DATE(E) DATE(J) DATE(M) DATE(O) DATE(S) DATE(U) DATE(W) /* /* /* /* /* /* /* /* /* /* returns returns returns returns returns returns returns returns returns returns 733209 3091 169 06/17/2008 2008169 June 2008/06/17 20080617 06/17/2008 Tuesday */ */ */ */ */ */ */ */ */ */
DELSTR(string,start,length). Returns the remains of a string when the characters from start for length characters are removed. SAY DELSTR(GOLDENEYES,5,2) /* returns GOLDEYES. */ DELWORD(string,start-word,how-many-words). Returns the remains of a string when words (groups of characters surrounded by spaces) are removed from the original string. The words deleted start at the start-word word for how-many-words characters are removed. SAY DELWORD(HI HOW ARE YOU,2,2) /* returns HI YOU */
DIAGRC(rc,command) (CMS only). Returns an explanation of the return code from the command sent to CMS. A return code from the command processor is included in the first eleven bytes of the reply. SAY DIAGRC(8,QUERY READER) returns 0 0 NO RDR FILES DIGITS(). Returns the current setting of NUMERIC DIGITS. NUMERIC DIGITS 7 SAY DIGITS() /* returns 7 */ D2C(number). Converts the decimal number to a hex number, and then returns the character for that hexadecimal code. SAY D2C(194) SAY D2C(240) /* returns B */ /* returns 0 */
D2X(number). Converts the decimal number into its hexadecimal equivalent. SAY D2X(240) /* returns F0 */
ERRORTEXT(number). Returns the REXX syntax message for the passed error number. SAY ERRORTEXT(16) /* returns LABEL NOT FOUND */
EXTERNALS(). Returns the number of elements in the terminal input buffer (how many lines are there). In VM/CMS, this number can be greater than zero; in TSO, because there is no type-ahead buffer REXX returns zero.. SAY EXTERNALS() /* returns 0, usually */
FIND(string,findstring). Returns the word number of the first word of findstring in string. SAY FIND(To be or not to be,not to be) Returns 4 as the NOT is the fourth word in the string.
FORM(). Returns the current setting of NUMERIC FORM. NUMERIC FORM SCIENTIFIC SAY FORM() /* returns SCIENTIFIC */ FORMAT(number,before decimal,after decimal). Allows the formatting of a number. The before number is the number of digits, blank-padded in front, appearing before the decimal point. The after number is the number of digits, padded with zeroes, appearing after the decimal point. LongNum = 1 / 3 ShortNum = 1 / 2 SAY FORMAT(LongNum,3,2) SAY FORMAT(ShortNum,2,4)
FUZZ(). Returns the current setting of NUMERIC FUZZ. NUMERIC FUZZ 2 SAY FUZZ() /* returns 2 */ INDEX(string,findstring). Returns the position of the start of findstring within string. A = A rose by any other name would smell as sweet Say INDEX(A,smell) /* returns 32 */ INSERT(string1,string2,position). Inserts string1 into string2 at the indicated position. Say INSERT(E,ABCDF,4) /* returns ABCDEF */
JUSTIFY(string,length,pad). Creates a new string using string of length characters. Justifies to both margins by adding blanks between words. If pad is used, that character will be the fill character instead of blanks, which is the default. Say JUSTIFY(Hello Kitty,20) Returns Hello Kitty Say JUSTIFY(Hello My Baby,20,?) Returns Hello?????My????Baby
LASTPOS(string1,string2). Returns the position of the last occurrence of string2 within string1. Returns a zero if string2 is not found within string1. A = Left, Left, Left Right Left Say LASTPOS(A,Left) /* returns 24 */ Say LASTPOS(A,Center) /* returns 0 */ LEFT(string,length,pad). Creates a new string using the leftmost length characters of string. By default, the string is padded to the right with spaces if string is shorter than length. If pad is supplied it will be the pad character. Say LEFT(Hello Kitty,2) Say LEFT(Hello,10,?) /* returns He */ /* returns Hello????? */
LENGTH(string). Returns the length of string in bytes. Say LENGTH(Hello Kitty) /* returns 11 */
LINESIZE(). Returns the length of the terminal line width, minus 1. Say LINESIZE() /* returns 79 on TSO, 80 on CMS */
LISTDSI (TSO only). Returns information about the dataset in REXX variables. See the following pages for a list of those variables and for the return codes set by LISTDSI. It can be used in two ways. RetCode = LISTDSI(dsn) or CALL LISTDSI dsn RetCode = RESULT There is an optional argument, DIRECTORY, which tells LISTDSI to provide information regarding the directory of a PDS (but not of a PDS-E). The syntax is RetCode = LISTDSI(dsn) DIRECTORY. RetCode = LISTDSI(dsn) /* sets variables */ Say SYSVOLUME /* displays the VOLSER */ Say SYSRECFM /* displays the record format */ Say SYSLRECL /* displays the record length */
Variables set by LISTDSI are listed here. Note all dates are returned as Julian dates using a slash (/). For example, 2006/107 is April 17, 2006. SYSDSNAME SYSVOLUME SYSUNIT SYSDSORG Dataset name VOLSER Device type of VOLSER Dataset organization DA = Direct Access (BDAM) PO = PDS or PDS-E PS = sequential VS = VSAM Record format F = Fixed length V = Variable length A = contains ASA characters B = Blocked Logical record length Blocksize (VS is VSAM) Key length or zero Total space allocated Total space used Primary space allocation Secondary space allocation Type of space allocation Cylinders Tracks Blocks Total extents used Creation date Last reference date Expiration date or 0 Password protection NONE = no password needed READ = read password needed WRITE = write password needed RACF protection status NONE = no protection GENERIC = generic profile DISCRETE = discrete profile YES or NO # of tracks / cylinder on VOLSER # of blocks / track on VOLSER # of directory blocks on a PDS # of used directory blocks # of members in the PDS reason code for command failure
SYSRECFM
SYSRACFA
LISTDSI return codes are listed here. The first-level system error message is in the variable SYSMSGLVL1; the second-level system error message is in the variable SYSMSGLVL2. 0) Success! 1) REXX had a problem analyzing the statement 2) Dynamic allocation failure 3) Cannot process this type of dataset 4) Error occurred obtaining unit name 5) Dataset is not catalogued 6) Error occurred getting dataset name 7) Error occurred getting unit type 8) Dataset is not on disk 9) Dataset is migrated and cannot be recalled 10) 11) Unauthorized to obtain directory information 12) VSAM dataset 13) Open error 14) Device type not found in MVS 15) 16) Command did not work 17) Some sort of abend 18) Incomplete information obtained 19) Multi-volume dataset 20) Unknown device type 21) Catalog error 22) Volume not mounted 23) I/O error attempting to get dataset information 24) Dataset not on catalogued volume 25) Dataset is migrated and is unavailable 26) Dataset is on a mass storage device 27) Cannot find VOLSER for this dataset 28) DD name specified is not valid 29) Neither dataset name nor DD name was provided MAX(number1,number2,number20). Returns the maximum number in a string of numbers. Note the numbers must be provided; variable substitution is not allowed. Say MAX(5,4,3,2,4,8,2) /* returns 8 */
MIN(number1,number2,number20). Returns the maximum number in a string of numbers. Note the numbers must be provided; variable substitution is not allowed. Say MIN(5,4,3,2,4,8,2) /* returns 2 */
MSG(), TSO only. Returns the MSG status of your TSO session. Alternatively, sets the MSG status of your session. When MSG is on, TSO command messages are displayed; when MSG is off, those messages are suppressed. TM = MSG(OFF) OM = MSG(ON) Say MSG() TM = MSG(OM) Say MSG() /* /* /* /* /* turn MSG off saves old status and sets it ON returns ON sets status to whatever is in OM returns OFF (see Line 1 and 2) */ */ */ */ */
MVSVAR(system-variable), TSO only. Retrieves information about the MVS system, one variable at a time. This is the list of system variables you can display. SYSAPPCLU: SYSDFP : SYSMVS : SYSNAME : SYSOPSYS : SYSSECLAB: SYSSMFID : SYSSMS : SYSCLONE : SYSPLEX : SYMDEF : the APPC/MVS logical unit (LU) name. the level of MVS/Data Facility Product (MVS/DFP). the level of the base control program (BCP) component of z/OS. the name of the system your REXX exec is running on, as specified in the SYSNAME statement in SYS1.PARMLIB member IEASYSxx. the z/OS name, version, release, modification level, and FMID. the security label (SECLABEL) name of the TSO/E session. identification of the system on which System Management Facilities (SMF) is active. indicator whether DFSMS/MVS is available to your REXX exec. MVS system symbol representing its system name. the MVS sysplex name as found in the COUPLExx or LOADxx member of SYS1.PARMLIB. symbolic variables of your MVS system.
When using SYMDEF, you must supply both the word SYMDEF and the symbolic variable name. Variables must be defined in the SYS1.PARMLIB member IEASYMxx.
OUTTRAP, TSO only. Captures the output from most TSO commands into a stem variable you specify. The first entry of the stem variable, VAR.0, contains the number of lines of output. You can also specify the number of lines to trap, from none (suppress all messages) to all lines. NOTE: some programs, such as the CONCAT command, produce output that cannot be captured by OUTTRAP. OUTTRAP syntax is one of the following. TMP = OUTTRAP(LCDATA.) /* captures output lines from */ LISTC /* the LISTC in the stem variable LCDATA. */ CALL OUTTRAP LINES. LISTC /* same as the first example */
TMP = OUTTRAP(LCDATA.,10) /* capture only the first 10 */ LISTC /* lines of the LISTC output in LCDATA. */ TMP = OUTTRAP(LCDATA.,0) /* do not capture or display */ LISTC /* any lines of the LISTC output. */ TMP = OUTTRAP(OFF) /* turns off output trapping */
Here is an example of reading the lines of output, with certain assumptions. TMP = OUTTRAP(LCDATA.) LISTC ENT(MY.JCL.PDS) TMP = OUTTRAP(OFF) SAY There are LCDATA.0 lines of LISTC output. Say LCDATA.1 /* produces 0NONVSAM MYID.MY.JCL.PDS */ Say LCDATA.2 /* produces IN-CAT LOCAL.CATALOG */ Do I = 1 to LCDATA.0 Say LCDATA.I End /* DO group displays all lines from the LISTC */ NewString = OVERLAY(string1,string2,start-position). Replaces characters in string2 with string1, starting with the character position at start-position. This command is very useful when formatting output lines. Say OVERLAY(.,2007/102,5) Say OVERLAY(DO,CAT,1) VAR1 = Overlay(.,VAR1,10) /* displays 2007.102 */ /* displays DOT */
POS(string1,string2,start-position). Returns the position of string1 in string2, starting with the character position at start-position. It returns a zero if the string is not found. Say POS(BUT,DOG AND BUTTERFLY,1) /* displays 9 */ Say POS(BUT,DOG AND BUTTERFLY,10) /* displays 0 */ PROMPT(), TSO only. Returns the PROMPT status of your TSO session. Alternatively, sets the PROMPT status of your session. When PROMPT is on, TSO commands prompt the user for input if it is missing. When PROMPT is off, those messages are suppressed. TP = PROMPT(OFF) OP = PROMPT(ON) Say PROMPT() TP = MSG(OP) Say MSG() /* /* /* /* /* turn MSG off save old status, set it ON returns ON set status to whatever is in OP returns OFF (see Line 1 & 2 */ */ */ */ */
QUEUED(). Returns the number of lines in the stack. Say QUEUED() PUSH New Line Say QUEUED() /* assuming none, displays 0 */ /* put a new line in the stack. */ /* displays 1 */
RANDOM(min,max,seed). Returns a random number between min and max. Seed is an optional parameter to change the derivation of random numbers from the default. See the examples below. Note the same number is produced by the last two statements because seed is supplied. Say Say Say Say RANDOM(1,10) RANDOM(1,10) RANDOM(1,10,120345) RANDOM(1,10,120345) /* /* /* /* returns returns returns returns 5 8 2 2 */ */ */ */
REVERSE(string). Reverses the character order in string. Say REVERSE(DOG) /* displays GOD */
RIGHT(string,length,pad). Creates a new string using the rightmost length characters of string. By default, the string is padded to the left with spaces if string is shorter than length. If pad is supplied it will be the pad character. Say RIGHT(Hello Kitty,2) /* returns ty */ Say RIGHT(Hello Kitty,5,?) /* returns ???ty */ SIGN(number). Returns: 1 if the number is positive. 0 if the number is zero. -1 if the number is negative. /* returns -1 */
Say SIGN(-9)
SOURCELINE(linenumber). Returns the original program statement with line number linenumber. /* REXX PROGRAM FOR SOURCELINE */ ARG VAR1 Say SOURCELINE(2) /* returns ARG VAR1 */ SPACE(string,how-many,pad). Inserts how-many spaces between words in string. If how-many is zero, all spaces are stripped. Pad is optional; if specified, it is inserted instead of spaces. Say SPACE(THE FINAL FRONTIER,3) Displays THE FINAL FRONTIER Say SPACE(THE FINAL FRONTIER,3,!) Displays THE!!!FINAL!!!FRONTIER Say SPACE(THE FINAL FRONTIER,0) Displays THEFINALFRONTIER STORAGE(address,length,new-data). Displays the main storage of length bytes at address. New-data is optional; if specified, STORAGE inserts it into memory. BE VERY CAREFUL WITH THIS! It is wise to only display storage unless you know exactly what you are doing. Say STORAGE(000000,8) Displays the first 8 bytes of storage.
NewString = STRIP(string,option,character). Removes character from string based on option. By default, character is a space. Available options are: B removes both trailing and leading characters (the default). T removes only trailing characters. L removes only leading characters. BLANKS BLANKS )
Say STRIP( LOTS OF BLANKS Displays LOTS OF BLANKS Say STRIP(MYUSERID.MY.CNTL,,) Displays MYUSERID.MY.CNTL
,T)
As you can see from that last example, STRIP is useful for removing leading and trailing quotes from fully-qualified dataset names. NewString = SUBSTR(string,start,length,pad). Returns a part of string starting at start for a length of length bytes. The pad character is used if length is longer than the resulting substring. Say SUBSTR(BOOKS,1,3) Say SUBSTR(BOOKS,5,4,S) /* Displays BOO */ /* Displays SSSS */
NewString = SUBWORD(string,start,how-many-words). Returns a part of string starting at start that has how-many-words words. Say SUBWORD(BOOKS ARE MY FRIENDS,2,2) Displays ARE MY SYMBOL(name). Tells you if name is a variable, a literal, or an illegal symbol. Returns VAR if name is an assigned variable LIT if name is an assigned variable BAD if name is an assigned variable /* Displays LIT /* Displays VAR /* Displays BAD */ */ */
SYSDSN(dataset-name) , TSO only. Tells you if a dataset exists and its current status. Possible returns include: OK MEMBER SPECIFIED BUT DATASET NOT PDS MEMBER NOT FOUND DATASET NOT FOUND ERROR PROCESSING REQUESTED DATASET PROTECTED DATASET VOLUME NOT ON SYSTEM UNAVAILABLE DATASET INVALID DATASET NAME MISSING DATASET NAME A simple example of how SYSDSN might be used. /* REXX Quick JCL submit */ Arg MEMBER JCLPDS = MY.JCL.CNTL(MEMBER) PDSQ = SYSDSN(JCLPDS) Select When PDSQ = OK Then SUBMIT JCLPDS When Left(PDSQ,6) = MEMBER Then Say PDSQ Otherwise, Say Some problem with JCLPDS. Error is PDSQ. End
SYSVAR(system-variable), TSO only. Retrieves information about the system. This is a list of the variables you can discover. SYSPREF : SYSPROC : SYSUID : SYSLTERM: SYSWTERM: SYSENV : SYSICMD : the prefix assigned to not-fully-qualified dataset names. the logon procedure for the current session. the user ID of the person logged on. the length of the terminal screen. In batch, returns 0. the width of the terminal screen. In batch, returns 132. returns FORE (foreground) or BACK (background). returns the name of the running, implicitly called exec. If the call was explicit, SYSICMD returns null. SYSISPF : returns ACTIVE or NOT ACTIVE. SYSNEST : returns YES if the current program was called from another, NO if not. SYSPCMD : the most recently used TSO command processor. The value of SYSPCMD is EXEC (the EXEC command) or EDIT (the EXEC subcommand of EDIT). SYSSCMD : the most recently used TSO subcommand processor. The value may be null (if not a subcommand) or EXEC (if it was). SYSCPU : the number of CPU seconds used this session. SYSSRV : the number of service units used this session. SYSHSM : the status of DFHSM. Returns AVAILABLE or null. SYSJES : the name and level of JES. SYSLRACF: the level of RACF. If RACF is not installed, this is null. SYSRACF : returns AVAILABLE, NOT AVAILABLE, or NOT INSTALLED. SYSNODE : either the JES node name, -INACTIVE-, or -DOWNLEVEL- if the subsystem is not at least either JES2 SP4.3 or JES3 SP5.1.1. SYSTERMID: the terminal ID, or null if batch. SYSTSOE : the level of TSO. SYSDTERM: If double-byte character set (DBCS) is enabled, returns YES. SYSKTERM: if Katakana character set is enabled, returns YES. SYSPLANG: returns the 3-byte primary language setting. SYSSLANG: returns the 3-byte secondary language settings. SOLDISP : show solicited messages (operator replies). Value is YES or NO. UNSDISP : show unsolicited messages (operator replies). Value is YES or NO. SOLNUM and UNSNUM: the size of the TSO message table. MFTIME : show a time stamp with each message. YES or NO. MFOSNM : show originating system name with each message. YES or NO. MFJOB : display the originating job name. YES or NO. MFSNMJBX: did the user request NOT to show the originating job and system names of a message. YES means DO NOT show the names; NO means to show them.
TIME(option). Returns the current time in a specific format based on the option below. TIME() : TIME(E): TIME(E): E. TIME(H): TIME(M): TIME(R): TIME(S): hh:mm:ss first time, starts the elapsed time counter second time, displays the number of seconds since the first hours since midnight minutes since midnight Resets elapsed time to zero. Seconds since midnight
TRACE(). Returns the current TRACE setting. TR = TRACE(O) DO FOREVER <instructions> END TR = TRACE(TR) SAY TRACE() /* save setting and turn TRACE off */ /* large loop */ /* set trace back to what it was /* displays current trace setting */ */
NewString = TRANSLATE(string,output table,input table). Converts any occurrence of character 1 in the input table to character 1 of the output character, and so on. Example: SAY TRANSLATE(ABCDEF,ZYXWV,ABCDE) displays ZYXWVF NewNum = TRUNC(number,decimal places). Returns the number with the given number of decimal places. Fills with spaces or zeroes as needed. Examples: SAY TRUNC(12.654,2) SAY TRUNC(12.654,4) SAY TRUNC(12.654,0) /* displays 12.65 */ /* displays 12.6540 */ /* displays 12 */
USERID(). Returns the ID you are logged on with. SAY USERID /* displays ISDODEA */
VALUE(). Returns the contents of a symbol after resolving it as a variable. PROGLANG = COBOL COBOL = English-like Say VALUE(PROGLANG) /* displays COBOL */ Say VALUE(PROGLANG) /* displays English-like */ VERIFY(string1,string2). Makes sure string1 is made up of the characters in string2. For example, this is a good way of verifying an arithmetic expression. IF VERIFY(input,'1234567890E+-*/% ().') = 0 THEN /* input is a valid arithmetic expression */ ELSE SAY input has invalid arithmetic characters. WORD(string,n). Returns the nth word in string. Say WORD(BOOKS ARE FUN,3) /* Displays FUN */
WORDINDEX(string,n). Returns the character position of the nth word in string. Say WORDINDEX(BOOKS ARE FUN,2) /* Displays 7 */
WORDLENGTH(string,n). Returns the length of the nth word in string. Say WORDLENGTH(BOOKS ARE FUN,2) /* Displays 3 */
WORDPOS(string1,string2,starting-word). Searches for string1 in string2, starting with starting-word and returns the number of words before string2. Say WORDPOS(VERY,BOOKS ARE VERY FUN) Displays 2 Say WORDPOS(ARE,BOOKS ARE VERY FUN,3) Displays 0
WORDS(string). Returns the number of words in string. Say WORDS(BOOKS ARE VERY FUN) LINE = HOW ARE YOU? Say WORDS(LINE) /* displays 4 */ /* displays 3 */
XRANGE(start,end). Returns the hexadecimal characters between start and end, inclusive. Examples: Say XRANGE(A,F) /* displays ABCDEF */ Say XRANGE(F1X,F5X) /* displays 12345 */ IF XRANGE(00X,09X) = 00010203040506070809X The IF statement would evaluate as TRUE. X2C(hex-string). Returns the characters of the hex string. Say X2C(F1) /* displays 1 */ Say X2C(F1F1F8) /* displays 118 */ X2D(hex-string). Returns the decimal equivalent of the hex string. Say X2D(1F) Say X2C(11C) /* displays 17 */ /* displays 284 */