[USflag] The American Programmer [USflag]
Home Programming Books for Computer Professionals Privacy Terms
           Home   > Programming   > REXX Programming   > REXX and PRO/JCL
           Home   > Programming   > Manuals   > REXX Manuals   > REXX and PRO/JCL
           Home   > Programming   > Just Enough   > REXX and PRO/JCL

REXX and PRO/JCL

PRO/JCL (r) by Diversified Software is an amazing product for JCL management.

Running your program

Your programs will execute in the PRO/JCL environment. This environment must have been set up for you before you execute your program. The people who installed PRO/JCL will tell you what you must do to assure that this environment is available.
This means that you are executing your program one of these 3 ways:

1 - As an Edit macro

While editing your JCL, type your REXX program's name

on the command line (no "TSO")

==> jj jmp=myprog

To test, get into split screen.

your REXX program that you are developing on top half

the JCL to be processed on bottom half



2 - Through JCL in batch.

You specify the JCL to be processed, and the program name.

Your REXX program will have to be in a specific library for production (find out from tech support) and your own library for testing.

 

 

What REXX looks like

1. What does REXX look like when used with PROJCL?

- mostly like the normal REXX you're used to

- PRO/JCL is exchanging information with your REXX program

you use the DSSIAPI function call to talk to PRO/JCL

- program will very likely follow the logic model of the example below

- you will probably not use the stack/data queue

- you will probably use SAY and PULL only during testing, not production.

- you won't use EXECIO to read the JCL

but you may use it to read other files (tables, for example)

and to write to a log/summary/statistics file.

/* REXX JMP001 Check the JOB MSGCLASS */

howmany = DSSIAPI("JMPHowManyStmts") 1

 

Do n = 1 to (howmany) by 1 2

hstmt = DSSIAPI("JMPgetNthStmt",n) 3

keyword = DSSIAPI("JMPgetKeywordName", hstmt) 4

If keyword = "JOB" then cur_job_stmt = jmp_job(hstmt) 5

End

Exit 6

jmp_job: PROCEDURE 7

job_stmt = ARG(1) 8

msgclassvalue = DSSIAPI("JMPgetValue", job_stmt, "MSGCLASS")

If (msgclassvalue <> 'X') then do 9

error = DSSIAPI("JMPaddError", job_stmt, 90444,20,,

"ERROR - Job msgclass must be X") 10

End

Return job_stmt 11

 

This example taken from PRO/JCL Facility Guide, pg 52. Slightly modified.

 

 

 

Explanation of the example on the previous page

1. Start off by asking PRO/JCL how many JCL statements there are. Not lines of code, but JOB, EXEC, DD, JCLLIB, SET, PROC, PEND, OUTPUT, etc.

DSSIAPI("JMPHowManyStmts") is a function call to PRO/JCL. You talk to PRO/JCL with function calls like this.

2. Loop as many times as there are statements in the JCL file. The parentheses around howmany are not required. The "by 1" is not required. It is the default.

3. This gets the n'th statement. Each time through, it gets the next JCL statement. Actually, it doesn't get the statement, it gets a handle to the statement. "hstmt"

When you read the PRO/JCL JMP Facility Guide you'll see that some functions return a value, while others return a handle.

I suggest starting the name with an "h" because it's a handle. (The original example doesn't have the "h")

What's a handle? A handle is a pointer or reference to the actual statement. It isn't the actual statement. If you looked at a handle you would not see JCL. That's all right - PRO/JCL can handle it!

The next line of the program gives the handle "hstmt" back to PRO/JCL.

Don't change a handle.

If you assign a handle to a variable, the variable becomes a handle

my_var = hstmt

4. PRO/JCL gives you the actual JCL keyword. (JOB, EXEC, DD, etc). "keyword" is not a handle - it's a normal REXX variable.

5. This asks if PRO/JCL is looking at a JOB statement. The two equal signs (==) are not necessary. Just 1 will work as well.

I put quotes around "JOB" because that is the standard way of doing it. Your program is very likely going to have more than one of these IF statements, like this:

if keyword = "JOB" then call job_subroutine

if keyword = "EXEC" then call exec_subroutine

if keyword = "DD" then call dd_subroutine

A SELECT is a better idea than having many IF's.

SELECT

when keyword = "JOB" then call job_subroutine

when keyword = "EXEC" then call exec_subroutine

when keyword = "DD" then call dd_subroutine

when keyword = ...etc

otherwise say "unexpected statement keyword"

end

6. EXIT before the subroutines. Pretty standard REXX.

7. Your subroutine, or function. (Either name is ok). The word PROCEDURE hides all the variables found in the subroutine. This is not required, but a good idea. Using it means that variables are not shared with the main part of the program. Data can only go into the subroutine through the ARG and leave it through the RETURN.

 

8. ARG(1) reads the first item or parameter, or argument passed to the subroutine. Commas separate the items.

Another way of doing this is:

ARG jmp_stmt, other_item_if_any

instead of job_stmt = ARG(1)

other_item = ARG(2)

Technically, ARG(1) gives you the first argument string; ARG(2) the second, etc.

The function ARG() gives you the number of argument strings that are present.

Note: commas separate argument strings, not spaces.

9. The parentheses around the things being compared are not needed. Nothing wrong with that style.

10. The two commas - the last one is for continuation. The first one is needed to separate the items being passed.

11. A subroutine or function always ends with a return If you put something after the return it is passed back to the calling statement.

 

Style

It is a good idea if everyone uses the same programming style.

These suggestions are mostly patterned after the examples in the JMP Facility Guide.

If you don't follow these suggestions, your program will work regardless.

 

1. Use lower case for REXX variables and handles.

keyword

2. Use an initial capital for the first REXX verb on the line. (This is nowhere near as important as the others)

If keyword = "JOB"

3. Put quotation marks around literal strings. Make the literal strings all capital letters.

If keyword = "JOB"

4. All JCL code must be in upper case.

new_msgclass = "A"

5. Prefix handles with an h.

hstmt

6. Use mixed case for API calls

hstmt = DSSIAPI("JMPgetNthStmt",n)

7. Use one equal sign (=) for comparisons. Many of the examples in the book show two (==).

if keyword = "JOB"

8. Don't use semicolons at the end of the line. They are not needed. Use them only when you have more than one verb on a line.

9. Use <> for the "Not Equal" operator. /=, ^=, \= work as well. Good idea if everyone uses the same one.

 

10. Indent IF and ELSE the same number of columns. Indent the dependent statements and their end the same amount. There is a lot of room for different styles here.

If a = 1 then do

  say "It is equal"

  say "really equal"...

end

Else do

  say "It is equal"

  say "really equal"...

end

11. To invoke a subroutine or function, use CALL when you don't need any result.

Use the function invocation if you need a result.

say myfunction(parameters)

or

variable = myfunction(parameters)

12. Don't use the PROCEDURE in subroutines / functions.

13. TSO commands in all capitals.

"DELETE TEMP.FILE"

 

Example of a program that works

This is an actual JMP. It validates MSGCLASS and drops any NOTIFY that there might be in the JCL.

/* rexx pj001 projcl test program

*/

howmany = DSSIAPI("JMPHowManyStmts")

/*say howmany "statements in this member"*/

do n = 1 to howmany

  hstmt = DSSIAPI("JMPGetNthStmt" , n)

  /*say hstmt "is statement handle (aren't you glad you looked?)"*/

  keyword = DSSIAPI("JMPgetKeywordName", hstmt)

  /*say "currently looking at JCL keyword " keyword */

  if keyword = "JOB" then call process_job hstmt

end n

exit

process_job:

arg hjob_stmt

temp = DSSIAPI("JMPsetValue", hjob_stmt, "CLASS", "Y")

call process_msgclass

call process_notify

return

process_msgclass:

msgclassvalue = DSSIAPI("JMPgetValue", hjob_stmt, "MSGCLASS")

if JPRC <> "OK" then do

  error_message = "ERROR - JOB MSGCLASS MUST BE coded X OR T"

  temp = DSSIAPI("JMPaddError", hjob_stmt, 90044, 20, error_message)

  temp = DSSIAPI("JMPaddKeywordParm", hjob_stmt, "MSGCLASS", "T")

  /*say error_message */

end

if msgclassvalue = "X" | ,

msgclassvalue = "T" ,

then nop

else do

  error_message = "ERROR - JOB MSGCLASS MUST BE X OR T"

  temp = DSSIAPI("JMPaddError", hjob_stmt, 90044, 20, error_message)

  /*say error_message */

end

return /* process_msgclass*/

process_notify:

notifyvalue = DSSIAPI("JMPgetValue", hjob_stmt, "NOTIFY")

if JPRC = "OK" then do

  error_message = "ERROR - JOB NOTIFY MUST BE NOT BE CODED"

  temp = DSSIAPI("JMPaddError", hjob_stmt, 90044, 20, error_message)

  temp = DSSIAPI("JMPdeleteParm", hjob_stmt, "NOTIFY")

end

return /* process_notify */

 

Method of doing a table lookup

USERID.GABE.EXEC(PROJCL1)

/* REXX PROJCL1

USE THIS METHOD OF DOING A TABLE LOOKUP

INSTEAD OF THE ONE ON PAGE 140 IN THE JMP FACILITY GUIDE

*/

TABLE. = "INVALID"

TABLE.7356 = "Q"

TABLE.6352 = "B"

TABLE.5362 = "A"

TABLE.6738 = "X"

TABLE.1234 = "X"

DO 5

  SAY "ENTER AN ACCOUNT NUMBER "

  PULL ACCT1

  SAY "ENTER A CLASS CODE "

  PULL CLASS

  IF TABLE.ACCT1 = CLASS THEN SAY "VALID"

  ELSE SAY "NOT VALID"

END

 

Doing a table lookup. Another example.

USERID.GABE.EXEC(PROJCL2)

/* REXX PROJCL2

USE THIS METHOD OF DOING A TABLE LOOKUP

INSTEAD OF THE ONE ON PAGE 140 IN THE JMP FACILITY GUIDE

THIS USES AN EXTERNAL FILE TO LOAD THE TABLE

THE CONTENTS OF THE EXTERNAL FILE ARE:

/* REXX */

TABLE. = "INVALID"

TABLE.7356 = "Q"

TABLE.6352 = "B"

TABLE.5362 = "A"

TABLE.6738 = "X"

TABLE.1234 = "X"

*/

"ALLOC DDN(TABLEIN) SHR REUSE DSN('userid.sample.data(PROJCL2)')"

"EXECIO * DISKR TABLEIN (STEM TABLEIN. FINIS)"

"FREE DDN(TABLEIN)"

DO I = 1 TO TABLEIN.0

  INTERPRET TABLEIN.I

END I

 

DO 5

  SAY "ENTER AN ACCOUNT NUMBER "

  PULL ACCT1

  SAY "ENTER A CLASS CODE "

  PULL CLASS

IF TABLE.ACCT1 = CLASS THEN SAY "VALID"

ELSE SAY "NOT VALID"

END

PRO/JCL is a registered trademark of Diversified Software Systems, Inc. Diversified Software Systems. TSO, REXX, DB2, UDB, MVS, OS/390 are registered trademarks of the IBM Corporation.
[Books Computer]

Home Programming Books for Computer Professionals Privacy Terms Contact |
Site Map and Site Search Programming Manuals and Tutorials The REXX Files Top of Page |

[link page]