Calling the Rexx Interpreter

A Rexx program can be run directly from the command prompt of the operating system, or from within an application.

From the Operating System

You can run a Rexx program directly from the operating system command prompt using Rexx followed by the program name. See Running a Rexx Program.

From within an Application

The Rexx interpreter is a dynamic-link library (DLL) routine (or Unix/Linux shared object). Any application can call the Rexx interpreter to run a Rexx program. The interpreter is fully reentrant and supports Rexx procedures running on several threads within the same process.

A C-language prototype for calling Rexx is in the Rexx.H include file.

The RexxStart Function

RexxStart calls the Rexx interpreter to run a Rexx procedure.

retc = RexxStart(ArgCount, ArgList, ProgramName, Instore, EnvName,
                 CallType, Exits, ReturnCode, Result);

Parameters

ArgCount (LONG) - input

is the number of elements in the ArgList array. This is the value that the ARG() built-in function in the Rexx program returns. ArgCount includes RXSTRINGs that represent omitted arguments. Omitted arguments are empty RXSTRINGs (strptr is null).

ArgList (PRXSTRING) - input

is an array of RXSTRING structures that are the Rexx program arguments.

ProgramName (PSZ) - input

is the address of the ASCII name of the Rexx procedure. If Instore is null, ProgramName must contain at least the file name of the Rexx procedure. You can also provide an extension, drive, and path. If you do not specify a file extension, the default is .CMD. A Rexx program can use any extension. If you do not provide the path and the drive, the Rexx interpreter uses the usual file search (current directory, then environment path).

If Instore is not null, ProgramName is the name used in the PARSE SOURCE instruction. If Instore requests a Rexx procedure from the macrospace, ProgramName is the macrospace function name (see Macrospace Interface).

Instore (PRXSTRING) - input

is an array of two RXSTRING descriptors for in-storage Rexx procedures. If the strptr fields of both RXSTRINGs are null, the interpreter searches for Rexx procedure ProgramName in the Rexx macrospace (see Macrospace Interface). If the procedure is not in the macrospace, the call to RexxStart terminates with an error return code.

If either Instore strptr field is not null, Instore is used to run a Rexx procedure directly from storage.

Instore[0]

is an RXSTRING describing a memory buffer that contains the Rexx procedure source. The source must be an exact image of a Rexx procedure disk file, complete with carriage returns, line feeds, and end-of-file characters.

Instore[1]

is an RXSTRING containing the translated image of the Rexx procedure. If Instore[1] is empty, the Rexx interpreter returns the translated image in Instore[1] when the Rexx procedure finishes running. The translated image may be used in Instore[1] on subsequent RexxStart calls.

If Instore[1] is not empty, the interpreter runs the translated image directly. The program source provided in Instore[0] is used only if the Rexx procedure uses the SOURCELINE built-in function. Instore[0] can be empty if SOURCELINE is not used. If Instore[0] is empty and the procedure uses the SOURCELINE built-in function, SOURCELINE() returns no lines and any attempt to access the source returns Error 40.

If Instore[1] is not empty, but does not contain a valid Rexx translated image, unpredictable results can occur. The Rexx interpreter might be able to determine that the translated image is incorrect and translate the source again.

Instore[1] is both an input and an output parameter.

If the procedure is executed from disk, the Instore pointer must be null. If the first argument string in Arglist contains the string //T and the CallType is RXCOMMAND, the interpreter performs a syntax check on the procedure source, but does not execute it and does not store any images.

The program calling RexxStart must release Instore[1] using RexxFreeMemory(ptr) when the translated image is no longer needed.

Only the interpreter version that created the image can run the translated image. Therefore, neither change the format of the translated image of a Rexx program, nor move a translated image to other systems or save it for later use. You can, however, use the translated image several times during a single application execution.

EnvName (PSZ) - input

is the address of the initial ADDRESS environment name. The ADDRESS environment is a subcommand handler registered using RexxRegisterSubcomExe or RexxRegisterSubcomDll. EnvName is used as the initial setting for the Rexx ADDRESS instruction.

If EnvName is null, the file extension is used as the initial ADDRESS environment. The environment name cannot be longer than 250 characters.

CallType (LONG) - input

is the type of the Rexx procedure execution. Allowed execution types are:

RXCOMMAND

The Rexx procedure is a system or application command. Rexx commands usually have a single argument string. The Rexx PARSE SOURCE instruction returns COMMAND as the second token.

RXSUBROUTINE

The Rexx procedure is a subroutine of another program. The subroutine can have several arguments and does not need to return a result. The Rexx PARSE SOURCE instruction returns SUBROUTINE as the second token.

RXFUNCTION

The Rexx procedure is a function called from another program. The subroutine can have several arguments and must return a result. The Rexx PARSE SOURCE instruction returns FUNCTION as the second token.

Exits (PRXSYSEXIT) - input

is an array of RXSYSEXIT structures defining exits for the Rexx interpreter to be used. The RXSYSEXIT structures have the following form:

typedef struct {
   PSZ             sysexit_name;  /* name of exit handler        */
   LONG            sysexit_code;  /* system exit function code   */
} RXSYSEXIT;

The sysexit_name is the address of an ASCII exit handler name registered with RexxRegisterExitExe or RexxRegisterExitDll. Sysexit_code is a code identifying the handler exit type. See System Exit Interface for exit code definitions. An RXENDLST entry identifies the system-exit list end. Exits must be null if exits are not used.

ReturnCode (PSHORT) - output

is the integer form of the Result string. If the Result string is a whole number in the range -(2**15) to 2**15-1, it is converted to an integer and also returned in ReturnCode.

Result (PRXSTRING) - output

is the string returned from the Rexx procedure with the Rexx RETURN or EXIT instruction. A default RXSTRING can be provided for the returned result. If a default RXSTRING is not provided or the default is too small for the returned result, the Rexx interpreter allocates an RXSTRING using GlobalAlloc(size). The caller of RexxStart is responsible for releasing the RXSTRING storage with RexxFreeMemory(ptr).

The Rexx interpreter does not add a terminating null to Result.

Return Codes

The possible RexxStart return codes are:

negative

Interpreter errors. See the Appendix in the Open Object Rexx: Reference for the list of Rexx errors.

0

No errors occurred. The Rexx procedure ran normally.

positive

A system return code that indicates problems finding or loading the interpreter. See the return codes for the Windows functions LoadLibrary and GetProcAddress for details.

When a macrospace Rexx procedure (see Macrospace Interface) is not loaded in the macrospace, the return code is -3 ("Program is unreadable").

Example

LONG      return_code;                 /* interpreter return code    */
RXSTRING  argv[1];                     /* program argument string    */
RXSTRING  retstr;                      /* program return value       */
SHORT     rc;                          /* converted return code      */
CHAR      return_buffer[250];          /* returned buffer            */

                                       /* build the argument string  */
   MAKERXSTRING(argv[0], macro_argument,
       strlen(macro_argument));
                                       /* set up default return      */
   MAKERXSTRING(retstr, return_buffer, sizeof(return_buffer));

   return_code = RexxStart(1,          /* one argument               */
                          argv,        /* argument array             */
                          "CHANGE.ED", /* Rexx procedure name        */
                          NULL,        /* use disk version           */
                          "Editor",    /* default address name       */
                          RXCOMMAND,   /* calling as a subcommand    */
                          NULL,        /* no exits used              */
                          &rc,         /* converted return code      */
                          &retstr);    /* returned result            */

                                       /* process return value       */
...
   RexxWaitForTermination();
                                       /* need to return storage?    */
   if (RXSTRPTR(retval) != return_buffer)
     GlobalFree(RXSTRPTR(retval));     /* release the RXSTRING       */

When RexxStart is executed within an external program (usually a C program), it runs synchronously with the main Rexx activity (thread) that it started. That is, when the main activity terminates, RexxStart returns, and the external program continues running.

To run RexxStart asynchronously, you can start several concurrent activities from the main activity using START or REPLY (see Concurrency). RexxStart is still synchronous to the main activity, that is, it returns when the main activity terminates, but it is asynchronous to the concurrent activities. If a concurrent activity runs longer than the main activity, RexxStart returns when the main activity ends, but the concurrent activity continues to run.

If, however, a concurrent activity is still running when the external program ends, the activity is terminated. To ensure that all activities finish executing, use RexxWaitForTermination or a looped RexxDidRexxTerminate in your external program after RexxStart. The use of RexxWaitForTermination is recommended also for programs that are not expected to use concurrency.

The following example demonstrates how to call MyCMD.CMD from a Cobol program (Rexx is running in the same process as the Cobol program).

       PROCESS PGMNAME(MIXED)
      * You need to specify Rexx.LIB when you link this program,
      * for example on the COB2 command.
      * Note that the name RexxStart, used later, is case-sensitive,
      * and requires the PGMNAME(MIXED) compiler option.
      *************************************************************
       IDENTIFICATION DIVISION.
      *************************************************************
       PROGRAM-ID.    'CALLRexx'
       AUTHOR.        IBM VISUALAGE FOR COBOL.

      *************************************************************
      *NAME:     CALLRexx                                       ***
      *                                                         ***
      *FUNCTION: CALL A Rexx PROCEDURE NAME XXXXXXXX,           ***
      *          PASSING ARGUMENT AND GETTING RETURNED DATA.    ***
      *                                                         ***
      *EXTERNAL SUBROUTINES: NONE                               ***
      *COPY MEMBERS: NONE                                       ***
      *                                                         ***
      *************************************************************

      *************************************************************
       ENVIRONMENT DIVISION.
      *************************************************************
       CONFIGURATION SECTION.

      *************************************************************
       DATA DIVISION.
      *************************************************************

       WORKING-STORAGE SECTION.

      *************************************************************
      *  INTERNAL VARIABLES                                       *
      *************************************************************

       01  WS-WORK-FIELDS.
           05  WS-RESULT-AREA          PIC X(255)     VALUE SPACES.
           05  WS-ARGUMENT-AREA        PIC X(255)     VALUE SPACES.
           05  WS-PARM1                PIC X(50)      VALUE '55'.
           05  WS-PARM2                PIC X(8)       VALUE '66'.
       01  WS-RexxSTART-PARAMETERS.
           05  WS-Rexx-ARGUMENT-COUNT  PIC S9(9)      VALUE +1  COMP-5.
           05  WS-Rexx-ARGUMENT-LIST.
               10  WS-ARG-LENGTH       PIC  9(9)      COMP-5.
               10  WS-ARG-POINTER                     POINTER.
           05  WS-Rexx-PROGRAM-NAME    PIC X(255)     VALUE LOW-VALUES.
           05  WS-Rexx-ENV-NAME        PIC X(20)      VALUE LOW-VALUES.
           05  WS-Rexx-RETURN-CODE     PIC S9(9)      VALUE 0   COMP-5.
           05  WS-Rexx-RESULT.
               10  WS-RESULT-LENGTH    PIC  9(9)      COMP-5.
               10  WS-RESULT-POINTER                  POINTER.
           05  WS-Rexx-INTERPRETER-RC  PIC S9(9)      COMP-5.

       LINKAGE SECTION.
       PROCEDURE DIVISION.
            SET WS-ARG-POINTER          TO ADDRESS OF WS-ARGUMENT-AREA.
            MOVE LENGTH OF WS-ARGUMENT-AREA
                                        TO WS-ARG-LENGTH.
            STRING WS-PARM1                  DELIMITED BY SPACE
                   ' '                       DELIMITED BY SIZE
                   WS-PARM2                  DELIMITED BY SPACE
                                             INTO WS-ARGUMENT-AREA
            END-STRING.
            STRING 'MYCMD'                   DELIMITED BY SIZE
                   X'00'                     DELIMITED BY SIZE
                                             INTO WS-Rexx-PROGRAM-NAME
            END-STRING.
            STRING 'CGISRV'                  DELIMITED BY SIZE
                   X'00'                     DELIMITED BY SIZE
                                             INTO WS-Rexx-ENV-NAME
            END-STRING.
            SET WS-RESULT-POINTER            TO
                                             ADDRESS OF WS-RESULT-AREA.
            MOVE LENGTH OF WS-RESULT-AREA    TO WS-RESULT-LENGTH.

      * Note that the name RexxStart is case sensitive
            CALL 'RexxStart'   USING
                         BY VALUE     WS-Rexx-ARGUMENT-COUNT
                         BY REFERENCE WS-Rexx-ARGUMENT-LIST
                         BY REFERENCE WS-Rexx-PROGRAM-NAME
                         BY VALUE     0
                         BY REFERENCE WS-Rexx-ENV-NAME
                         BY VALUE     0
                         BY VALUE     0
                         BY REFERENCE WS-Rexx-RETURN-CODE
                         BY REFERENCE WS-Rexx-RESULT
                         RETURNING    WS-Rexx-INTERPRETER-RC.
            DISPLAY WS-Rexx-RETURN-CODE ' ' WS-Rexx-INTERPRETER-RC.
            DISPLAY WS-RESULT-LENGTH.
            DISPLAY WS-RESULT-AREA.
            GOBACK.

The RexxWaitForTermination Function

RexxWaitForTermination waits for the termination of all activities of the program that were started by RexxStart. This function puts your program into a wait state. It cannot continue until the activities have finished.

RexxWaitForTermination();

The RexxDidRexxTerminate Function

RexxDidRexxTerminate checks for the termination of all activities of the program that were started by RexxStart, and allows your program to continue.

retc = RexxDidRexxTerminate();

Return Codes

0

Activities are still running.

1

All activities have been terminated.

Example

while (!RexxDidRexxTerminate())
{
   /* do your processing */
}