Subroutines Written in REXX

In this section:

How to:

Reference:

A request can call a subroutine coded in REXX. These subroutines, also called FUSREXX macros, provide a 4GL option to the languages supported for user-written subroutines.

REXX subroutines are supported in the z/OS environment. A REXX subroutine contains REXX source code. Compiled REXX code is not supported.

A REXX subroutine contains REXX source code. Compiled REXX code is not supported.

REXX subroutines are not necessarily the same in all operating environments. Therefore, some of the examples may use REXX functions that are not available in your environment.

Because of CPU requirements, the use of REXX subroutines in large production jobs should be monitored carefully.

For more information on REXX subroutines, see your REXX documentation.

Reference: Storing and Searching for a REXX Subroutine

To store a REXX subroutine, DDNAME FUSREXX must be allocated to a PDS. This library is searched before other z/OS libraries.

The search order for a REXX subroutine is:

  1. FUSREXX.
  2. Standard z/OS search order.

Syntax: How to Call a REXX Subroutine

DEFINE FILE filename						 
fieldname/{An|In} = subname(inlen1, inparm1, ..., outlen, outparm);
END

or

{DEFINE|COMPUTE} fieldname/{An|In} = subname(inlen1, inparm1, ...,  
outlen, outparm);

or

-SET &var = subname(inlen1, inparm1, ..., outlen, outparm);

where:

fieldname

Is the field that contains the result.

An, In

Is the format of the field that contains the result.

subname

Is the name of the REXX subroutine.

inlen1, inparm1 ...

Are the input parameters. Each parameter consists of a length and an alphanumeric parameter value. You can supply the value, the name of an alphanumeric field that contains the value, or an expression that returns the value. Up to 13 input parameter pairs are supported. Each parameter value can be up to 256 bytes long.

Dialogue Manager converts numeric arguments to floating-point double-precision format. Therefore, you can only pass alphanumeric input parameters to a REXX subroutine using -SET.

outlen, outparm

Is the output parameter pair, consisting of a length and a result. In most cases, the result should be alphanumeric, but integer results are also supported. The result can be a field or a Dialogue Manager variable that contains the value, or the format of the value enclosed in single quotation marks. The return value can be a minimum of one byte long and a maximum (for an alphanumeric value) of 256 bytes.

Note: If the value returned is an integer, outlen must be 4 because WebFOCUS reserves four bytes for integer fields.

&var

Is the name of the Dialogue Manager variable that contains the result.

Example: Returning the Day of the Week

The REXX subroutine DOW returns the day of the week corresponding to the date an employee was hired. The routine contains one input parameter pair and one return field pair.

DEFINE FILE EMPLOYEE 
1. AHDT/A6 = EDIT(HIRE_DATE) ; 
2. DAY_OF_WEEK/A9 WITH AHDT = DOW(6, AHDT, 9, DAY_OF_WEEK);
   END
TABLE FILE EMPLOYEE
PRINT LAST_NAME HIRE_DATE DAY_OF_WEEK
END

The procedure processes as follows:

  1. The EDIT function converts HIRE_DATE to alphanumeric format and stores the result in a field with the format A6.
  2. The result is stored in the DAY_OF_THE_WEEK field, and can be up to nine bytes long.

The output is:

LAST_NAME        HIRE_DATE  DAY_OF_WEEK
---------        ---------  -----------
STEVENS           80/06/02  Monday
SMITH             81/07/01  Wednesday
JONES             82/05/01  Saturday
SMITH             82/01/04  Monday
BANNING           82/08/01  Sunday
IRVING            82/01/04  Monday
ROMANS            82/07/01  Thursday
MCCOY             81/07/01  Wednesday
BLACKWOOD         82/04/01  Thursday
MCKNIGHT          82/02/02  Tuesday
GREENSPAN         82/04/01  Thursday
CROSS             81/11/02  Monday

The REXX subroutine appears below. It reads the input date, reformats it to MM/DD/YY format, and returns the day of the week using a REXX DATE call.

/* DOW routine. Return WEEKDAY from YYMMDD format date */
Arg ymd .
Return Date('W',Translate('34/56/12',ymd,'123456'),'U')

Example: Passing Multiple Arguments to a REXX Subroutine

The REXX subroutine INTEREST has four input parameters.

DEFINE FILE EMPLOYEE 
1. AHDT/A6     = EDIT(HIRE_DATE); 
2. ACSAL/A12   = EDIT(CURR_SAL); 
3. DCSAL/D12.2 = CURR_SAL; 
4. PV/A12    = INTEREST(6, AHDT, 6, '&YMD', 3, '6.5', 12, ACSAL, 12, PV);
   END
 
TABLE FILE EMPLOYEE
PRINT LAST_NAME FIRST_NAME HIRE_DATE DCSAL PV
END

The procedure processes as follows:

  1. EDIT converts HIRE_DATE to alphanumeric format and stores the result in AHDT.
  2. EDIT converts CURR_SAL to alphanumeric format and stores the result in ACSAL.
  3. CURR_SAL is converted to a floating-point double-precision field that includes commas, and the result is stored in DCSAL.
  4. The second input field is six bytes long. Data is passed as a character variable &YMD in YYMMDD format.

    The third input field is a character value of 6.5, which is three bytes long to account for the decimal point in the character string.

    The fourth input field is 12 bytes long. This passes the character field ACSAL.

    The return field is up to 12 bytes long and is named PV.

The output is:

LAST_NAME        FIRST_NAME  HIRE_DATE           DCSAL            PV
---------        ----------  ---------           -----            --
STEVENS          ALFRED       80/06/02       11,000.00      14055.14
SMITH            MARY         81/07/01       13,200.00      15939.99
JONES            DIANE        82/05/01       18,480.00      21315.54
SMITH            RICHARD      82/01/04        9,500.00      11155.60
BANNING          JOHN         82/08/01       29,700.00      33770.53
IRVING           JOAN         82/01/04       26,862.00      31543.35
ROMANS           ANTHONY      82/07/01       21,120.00      24131.19
MCCOY            JOHN         81/07/01       18,480.00      22315.99
BLACKWOOD        ROSEMARIE    82/04/01       21,780.00      25238.25
MCKNIGHT         ROGER        82/02/02       16,100.00      18822.66
GREENSPAN        MARY         82/04/01        9,000.00      10429.03
CROSS            BARBARA      81/11/02       27,062.00      32081.82

The REXX subroutine appears below. The REXX Format command is used to format the return value.

/* Simple INTEREST program. dates are yymmdd format  */
Arg start_date,now_date,percent,open_balance, .
 
begin = Date('B',Translate('34/56/12',start_date,'123456'),'U')
stop  = Date('B',Translate('34/56/12',now_date,'123456'),'U')
valnow = open_balance * (((stop - begin) * (percent / 100)) / 365)
 
Return Format(valnow,9,2)

Example: Accepting Multiple Tokens in a Parameter

A REXX subroutine can accept multiple tokens in a parameter. The following procedure passes employee information (PAY_DATE and MO_PAY) as separate tokens in the first parameter. It passes three input parameters and one return field.

DEFINE FILE EMPLOYEE 
1.  COMPID/A256 = FN | ' ' | LN | ' ' |  DPT | ' ' | EID ; 
2.  APD/A6 = EDIT(PAY_DATE); 
3.  APAY/A12 = EDIT(MO_PAY); 
4.  OK4RAISE/A1 = OK4RAISE(256, COMPID, 6, APD, 12, APAY, 1, OK4RAISE);
    END
 
TABLE FILE EMPLOYEE
PRINT EMP_ID FIRST_NAME LAST_NAME DEPARTMENT
IF OK4RAISE EQ '1'
END

The procedure processes as follows:

  1. COMPID is the concatenation of several character fields passed as the first parameter and stored in a field with the format A256. Each of the other parameters is a single argument.
  2. EDIT converts PAY_DATE to alphanumeric format.
  3. EDIT converts MO_PAY to alphanumeric format.
  4. OK4RAISE executes, and the result is stored in OK4RAISE.

The output is:

EMP_ID     FIRST_NAME         LAST_NAME      DEPARTMENT
------     ----------         ---------      ----------
071382660  ALFRED             STEVENS        PRODUCTION

The REXX subroutine appears below. Commas separate FUSREXX parameters. The ARG command specifies multiple variable names before the first comma and, therefore, separates the first FUSREXX parameter into separate REXX variables, using blanks as delimiters between the variables.

/* OK4RAISE routine. Parse separate tokens in the 1st parm, */
/* then more parms */
 
Arg fname lname dept empid,  pay_date,  gross_pay, .
 
If dept = 'PRODUCTION' & pay_date < '820000'
Then retvalue = '1'
Else retvalue = '0'
 
Return retvalue

REXX subroutines should use the REXX RETURN subroutine to return data. REXX EXIT is acceptable, but is generally used to end an EXEC, not a FUNCTION.

Correct
/* Some FUSREXX function */
Arg input
some rexx process ..
Return data_to_WebFOCUS
Not as Clear
/* Another FUSREXX function */
Arg input
some rexx process ...
Exit 0

Formats and REXX Subroutines

A REXX subroutine requires input data to be in alphanumeric format. Most output is returned in alphanumeric format. If the format of an input argument is numeric, use the EDIT or FTOA functions to convert the argument to alphanumeric. You can then use the EDIT or ATODBL functions to convert the output back to numeric.

The output length in the subroutine call must be four. Character variables cannot be more than 256 bytes. This limit also applies to REXX subroutines. FUSREXX routines return variable length data. For this reason, you must supply the length of the input arguments and the maximum length of the output data.

A REXX subroutine does not require any input parameters, but requires one return parameter, which must return at least one byte of data. It is possible for a REXX subroutine not to need input, such as a function that returns USERID.

A REXX subroutine does not support WebFOCUS date input arguments. When working with dates you can do one of the following:

Example: Returning a Result in Alphanumeric Format

The NUMCNT subroutine returns the number of copies of each classic movie in alphanumeric format. It passes one input parameter and one return field.

TABLE FILE MOVIES 
   PRINT TITLE AND COMPUTE  
1. ACOPIES/A3 = EDIT(COPIES); AS 'COPIES'
   AND COMPUTE 
2. TXTCOPIES/A8 = NUMCNT(3, ACOPIES, 8, TXTCOPIES);
   WHERE CATEGORY EQ 'CLASSIC'
   END

The procedure processes as follows:

  1. The EDIT field converts COPIES to alphanumeric format, and stores the result in ACOPIES.
  2. The result is stored in an 8-byte alphanumeric field TXTCOPIES.

The output is:

TITLE                                    COPIES  TXTCOPIES
-----                                    ------  ---------
EAST OF EDEN                             001     One
CITIZEN KANE                             003     Three
CYRANO DE BERGERAC                       001     One
MARTY                                    001     One
MALTESE FALCON, THE                      002     Two
GONE WITH THE WIND                       003     Three
ON THE WATERFRONT                        002     Two
MUTINY ON THE BOUNTY                     002     Two
PHILADELPHIA STORY, THE                  002     Two
CAT ON A HOT TIN ROOF                    002     Two
CASABLANCA                               002     Two

The subroutine is:

/* NUMCNT routine. */
/* Pass a number from 0 to 10 and return a character value */ 
Arg numbr .
data = 'Zero One Two Three Four Five Six Seven Eight Nine Ten'
numbr = numbr + 1           /* so 0 equals 1 element in array */
Return Word(data,numbr)

Example: Returning a Result in Integer Format

In the following example, the NUMDAYS subroutine finds the number of days between HIRE_DATE and DAT_INC and returns the result in integer format.

   DEFINE FILE EMPLOYEE 
1. AHDT/A6 = EDIT(HIRE_DATE); 
2. ADI/A6 = EDIT(DAT_INC); 
3. BETWEEN/I6 = NUMDAYS(6, AHDT, 6, ADI, 4, 'I6') ;
   END
 
TABLE FILE EMPLOYEE
PRINT LAST_NAME HIRE_DATE DAT_INC BETWEEN
IF BETWEEN NE 0
END

The procedure processes as follows:

  1. EDIT converts HIRE_DATE to alphanumeric format and stores the result in AHDT.
  2. EDIT converts DAT_INC to alphanumeric format and stores the result in ADI.
  3. NUMDAYS finds the number of days between AHDT and ADI and stores the result in integer format.

The output is:

LAST_NAME      HIRE_DATE   DAT_INC  BETWEEN
---------      ---------   -------  -------
STEVENS        80/06/02    82/01/01     578
STEVENS        80/06/02    81/01/01     213
SMITH          81/07/01    82/01/01     184
JONES          82/05/01    82/06/01      31
SMITH          82/01/04    82/05/14     130
IRVING         82/01/04    82/05/14     130
MCCOY          81/07/01    82/01/01     184
MCKNIGHT       82/02/02    82/05/14     101
GREENSPAN      82/04/01    82/06/11      71
CROSS          81/11/02    82/04/09     158

The subroutine appears below. The return value is converted from REXX character to HEX and formatted to be four bytes long.

/* NUMDAYS routine.  */
/* Return number of days between 2 dates in yymmdd format */
/* The value returned will be in hex format               */
 
Arg first,second .
 
base1 = Date('B',Translate('34/56/12',first,'123456'),'U')
base2 = Date('B',Translate('34/56/12',second,'123456'),'U')
 
Return D2C(base2 - base1,4)

Example: Passing a Date Value as an Alphanumeric Field With Date Options

In the following example, a date is used by passing an alphanumeric field with date options to the DATEREX1 subroutine. DATEREX1 takes two input arguments: an alphanumeric date in A8YYMD format and a number of days in character format. It returns a smart date in YYMD format that represents the input date plus the number of days. The format A8YYMD corresponds to the REXX Standard format ('S').

The number 693959 represents the difference, in number of days, between the WebFOCUS base date and the REXX base date:

/* REXX DATEREX1 routine. Add indate (format A8YYMD) to days */
Arg indate, days .
Return D2C(Date('B',indate,'S')+ days - 693959, 4)

The following request uses the DATEREX1 macro to calculate the date that is 365 days from the hire date of each employee. The input arguments are the hire date and the number of days to add. Because HIRE_DATE is in I6YMD format, it must be converted to A8YYMD before being passed to the macro:

TABLE FILE EMPLOYEE
PRINT LAST_NAME FIRST_NAME HIRE_DATE
AND COMPUTE
  ADATE/YYMD =  HIRE_DATE; NOPRINT
AND COMPUTE
  INDATE/A8YYMD= ADATE; NOPRINT
AND COMPUTE
  NEXT_DATE/YYMD = DATEREX1(8, INDATE, 3, '365', 4, NEXT_DATE);
BY LAST_NAME NOPRINT
END

The output is:

LAST_NAME        FIRST_NAME  HIRE_DATE  NEXT_DATE 
---------        ----------  ---------  --------- 
BANNING          JOHN         82/08/01  1983/08/01
BLACKWOOD        ROSEMARIE    82/04/01  1983/04/01
CROSS            BARBARA      81/11/02  1982/11/02
GREENSPAN        MARY         82/04/01  1983/04/01
IRVING           JOAN         82/01/04  1983/01/04
JONES            DIANE        82/05/01  1983/05/01
MCCOY            JOHN         81/07/01  1982/07/01
MCKNIGHT         ROGER        82/02/02  1983/02/02
ROMANS           ANTHONY      82/07/01  1983/07/01
SMITH            MARY         81/07/01  1982/07/01
SMITH            RICHARD      82/01/04  1983/01/04
STEVENS          ALFRED       80/06/02  1981/06/02

Example: Passing a Date as a Date Converted to Alphanumeric Format

In the following example, a date is passed to the subroutine as a smart date converted to alphanumeric format. The DATEREX2 subroutine takes two input arguments: an alphanumeric number of days that represents a smart date, and a number of days to add. It returns a smart date in YYMD format that represents the input date plus the number of days. Both the input date and output date are in REXX base date ('B') format.

The number 693959 represents the difference, in number of days, between the WebFOCUS base date and the REXX base date:

/* REXX DATEREX2 routine. Add indate (original format YYMD) to days */
Arg indate, days .
Return D2C(Date('B',indate+693959,'B') + days - 693959, 4)

The following request uses DATEREX2 to calculate the date that is 365 days from the hire date of each employee. The input arguments are the hire date and the number of days to add. Because HIRE_DATE is in I6YMD format, it must be converted to an alphanumeric number of days before being passed to the macro:

TABLE FILE EMPLOYEE
PRINT LAST_NAME FIRST_NAME HIRE_DATE
AND COMPUTE
  ADATE/YYMD =  HIRE_DATE; NOPRINT
AND COMPUTE
  INDATE/A8 = EDIT(ADATE); NOPRINT
AND COMPUTE
  NEXT_DATE/YYMD = DATEREX2(8,INDATE,3,'365',4,NEXT_DATE);
BY LAST_NAME NOPRINT
END

The output is:

LAST_NAME        FIRST_NAME  HIRE_DATE  NEXT_DATE 
---------        ----------  ---------  --------- 
BANNING          JOHN         82/08/01  1983/08/01
BLACKWOOD        ROSEMARIE    82/04/01  1983/04/01
CROSS            BARBARA      81/11/02  1982/11/02
GREENSPAN        MARY         82/04/01  1983/04/01
IRVING           JOAN         82/01/04  1983/01/04
JONES            DIANE        82/05/01  1983/05/01
MCCOY            JOHN         81/07/01  1982/07/01
MCKNIGHT         ROGER        82/02/02  1983/02/02
ROMANS           ANTHONY      82/07/01  1983/07/01
SMITH            MARY         81/07/01  1982/07/01
SMITH            RICHARD      82/01/04  1983/01/04
STEVENS          ALFRED       80/06/02  1981/06/02