fhg
Volume 8, Number 23 -- June 11, 2008

Seeking Advice on REXX

Published: June 11, 2008

Hey Bruce:

I want to call from CL program a REXX program, where the REXX program returns a calculate of date (yymmdd). Do you have an example you could send me?

Thanks in advance,

--Larry


Larry,

REXX can't directly return a value to CL the way other languages do. You'd have to have your REXX procedure write the data to a file or use the REXX External Data Queue.

To use a file you'd have to first override STDOUT to a file of your choice, then use "SAY" to write the data. In your REXX procedure you could do this:

'OVRDBF FILE(STDOUT) TOFILE(yourlib/yourfile) OVRSCOPE(*JOB)'
SAY value
'DLTOVR FILE(STDOUT) LVL(*JOB)'

Notice that I put the OVRDBF and DLTOVR in quotes. That way REXX treats them as CL commands. The "value" is whatever value you want returned. The layout of the file can be anything you want as REXX treats all files as flat (it doesn't understand "externally described").

To use the REXX External Data Queue you'll need to push the data to the queue in your REXX procedure, then do an API call in your CL to retrieve the data:

In REXX:

PUSH value

In CL, the length of &DATA and value of &LENGTH can be whatever you need (they just need to match):

DCL        VAR(&DATA) +
TYPE(*CHAR) +
LEN(50)   <=========
DCL        VAR(&LENGTH) +       |
TYPE(*INT) +       | The LEN and VALUE must match
LEN(4) +           |
VALUE(50) <=========
DCL        VAR(&RETURNCODE) +
TYPE(*INT) +
LEN(2)

CALL       PGM(QREXQ) +
PARM('P' &DATA &LENGTH 0 &RETURNCODE)

For more information you can check out my article, REXX Can Talk to Other Languages, which describes it in more detail.

--Bruce


Hi Bruce,

I just read your article, but I don't understand the different when using STRREXPRC, QREXX, or QREXQ. Could you tell me what is the correct form or option that I must to use (1, 2 or 3)

If I write the CL:

 PGM                                                    
 DCLF       FILE(SOPTEC400/DEP_QHST)    
 DCL        VAR(&FH) TYPE(*CHAR) LEN(6)                          
 DCL        VAR(&LEN) TYPE(*INT) LEN(6)
 DCL        VAR(&RETC) TYPE(*INT) LEN(2)                                   
 CHGCURLIB  CURLIB(SOPTEC400)                           
 MONMSG CPF0000                                         
 CLRPFM     FILE(*LIBL/DEP_QHST)                        
 DSPOBJD    OBJ(QSYS/QHST*) OBJTYPE(*FILE) +            
    OUTPUT(*OUTFILE) OUTFILE(*LIBL/DEP_QHST)  
PROCCESS: RCVF                                             
 MONMSG     MSGID(CPF0864) EXEC(GOTO CMDLBL(FIN))       
 CHGVAR     VAR(&FEC) VALUE(%SST(&ODOBTX 2 6))          
1-> STRREXPRC  SRCMBR(FECHA) SRCFILE(SOPTEC400/QREXSRC) PARM(&FH)  
2-> CALL       PGM(QREXX) PARM(FECHA     QREXSRC   SOPTEC400 &FH)
3-> CALL       PGM(QREXQ) PARM('P' &FH &LEN 0 &RETC)

In REXX:

parse value date('O') with aņo '/' mes '/' dia
d=dia-7; if length(d)<2 then d=0||d
FH=aņo||mes||d
return


Larry,

I'm guessing that the field FH is the value that you wish to return. With that in mind, here is what you need in your REXX. Before your "return" add the following line:

push FH   <=== This places the value in field FH
                into the External Data Queue

In your CL you should have the following:

DCL        VAR(&FH) TYPE(*CHAR) LEN(6)
DCL        VAR(&LEN) TYPE(*INT) LEN(4) VALUE(6)
DCL        VAR(&RETC) TYPE(*INT) LEN(2)

STRREXPRC  SRCMBR(FECHA) SRCFILE(SOPTEC400/QREXSRC)   <=== 

This executes your REXX:

CALL       PGM(QREXQ) PARM('P' &FH &LEN 0 &RETC)      <===

This retrieves the value that was "pushed" to the External Data Queue.

Notice that I removed the PARM from the STRREXPRC statement. PARMs can only be passed into REXX, not returned. If I understand your REXX procedure properly you are not passing a value in, simply calculating a date value and returning it. Also, I corrected your definition of field &LEN. It needs to be TYPE(*INT) LEN(4) with a VALUE indicating the length of the data being returned (which should match the LEN of field &FH). It is the VALUE that must match the LEN of &FH. This VALUE is passed to QREXQ and tells the program how much data to return.

One more thing, program QREXX is just another way to execute a REXX procedure (like STRREXPRC command does). So, you could replace your STRREXPRC command with a call to QREXX, but since you're using CL, there is no good reason to do that. If you were calling your REXX from RPG or COBOL, then it might make more sense.

Let me know if you have more questions.

--Bruce


Hi Bruce,

It's me again. Your advice worked. I prefer to work in REXX because I have worked 18 years with mainframe (VM and VSE), and my company just changed machines from zSeries for iSeries three years ago. But my co-workers do not know REXX, only CL. Is there some trick for doing the following in CL?

REXX:

l.1='LINEATM';l.2='LINEHSM';l.3='LINELOCAL';l.4='LINEVISA';l.5='LINEMC'
do k=1 to 5
   "VFYCFG CFGOBJ("l.k") CFGTYPE(*LIN) STATUS(*ON)"
end
exit

--Larry


Larry:

There is a way to do this in CL, but it is a bit more cumbersome than the REXX option. Also, it depends on what version of the OS you're at.

CL doesn't support arrays, but you can do something like it. If you're at V5R4 you can use pointers in CL, otherwise you'd need to use %SST.

In V5R4:

PGM

DCL	VAR(&LINES) TYPE(*CHAR) LEN(50) VALUE('LINEATM   LINEHSM   
LINELOCAL LINEVISA  LINEMC    ')   <== Each value is 10 long, 
                                        total 50 chars.
DCL	VAR(&LINEPTR) TYPE(*PTR) ADDRESS(&LINES)
DCL	VAR(&CURLINE) TYPE(*CHAR) STG(*BASED) LEN(10) BASPTR)&LINEPTR)

DCL	VAR(&I) TYPE(*UINT)

DOFOR	VAR(&I) FROM(1) TO(5)

CHGVAR	VAR(&LINEPTR) VALUE(&LINEPTR + ((&I - 1) * 10))

VRYCFG	CFGOBJ(&CURLINE) CFGTYPE(*LIN) STATUS(*ON)

ENDDO

ENDPGM

Before V5R4:

PGM

DCL	VAR(&LINES) TYPE(*CHAR) LEN(50) VALUE('LINEATM   LINEHSM   
LINELOCAL LINEVISA  LINEMC    ')   <== Each value is 10 long, 
                                        total 50 chars.
DCL	VAR(&LINEPOS) TYPE(*DEC) LEN(3 0) VALUE(0)
DCL	VAR(&CURLINE) TYPE(*CHAR) STG(*BASED) LEN(10) BASPTR)&LINEPTR)

DCL	VAR(&I) TYPE(*UINT)

DOFOR	VAR(&I) FROM(1) TO(5)

CHGVAR	VAR(&LINEPOS) VALUE(((&I - 1) * 10) + 1)
CHGVAR	VAR(&CURLINE) VALUE(%SST(&LINES &LINEPOS 10))

VRYCFG	CFGOBJ(&CURLINE) CFGTYPE(*LIN) STATUS(*ON)

ENDDO

ENDPGM

If you're at a release before DOFOR came out, you'll have to modify your logic to increment &I from 1 to 5, otherwise the second example stays the same. (I'll leave that to your co-workers.)

I haven't tested the above code, but it should be pretty close.

--Bruce


RELATED STORY

REXX Can Talk to Other Languages



Copyright © 1996-2008 Guild Companies, Inc. All Rights Reserved.
Guild Companies, Inc., 50 Park Terrace East, Suite 8F, New York, NY 10034

Privacy Statement