Registered System Exit Interface

The Rexx system exits let the programmer create a customized Rexx operating environment. You can set up user-defined exit handlers to process specific Rexx activities.

Applications can create exits for:

Exit handlers are similar to subcommand handlers and external functions. Applications must register named exit handlers with the Rexx interpreter. Exit handlers can reside in dynamic-link libraries or within an executable application module.

Writing System Exit Handlers

The following is a sample exit handler definition:

int REXXENTRY Rexx_IO_exit(
     int   ExitNumber,    /* code defining the exit function    */
     int   Subfunction,   /* code defining the exit subfunction */
     PEXIT ParmBlock);    /* function-dependent control block   */

where:

ExitNumber

is the major function code defining the type of exit call.

Subfunction

is the subfunction code defining the exit event for the call.

ParmBlock

is a pointer to the exit parameter list.

The exit parameter list contains exit-specific information. See the exit descriptions following the parameter list formats.

Note: Some exit subfunctions do not have parameters. ParmBlock is set to null for exit subfunctions without parameters.

Exit Return Codes

Exit handlers return an integer value that signals one of the following actions:

RXEXIT_HANDLED

The exit handler processed the exit subfunction and updated the subfunction parameter list as required. The Rexx interpreter continues with processing as usual.

RXEXIT_NOT_HANDLED

The exit handler did not process the exit subfunction. The Rexx interpreter processes the subfunction as if the exit handler were not called.

RXEXIT_RAISE_ERROR

A fatal error occurred in the exit handler. The Rexx interpreter raises Rexx error 48 ("Failure in system service").

For example, if an application creates an input/output exit handler, one of the following happens:

  • When the exit handler returns RXEXIT_NOT_HANDLED for an RXSIOSAY subfunction, the Rexx interpreter writes the output line to STDOUT.

  • When the exit handler returns RXEXIT_HANDLED for an RXSIOSAY subfunction, the Rexx interpreter assumes the exit handler has handled all required output. The interpreter does not write the output line to STDOUT.

  • When the exit handler returns RXEXIT_RAISE_ERROR for an RXSIOSAY subfunction, the interpreter raises Rexx error 48, "Failure in system service".

Exit Parameters

Each exit subfunction has a different parameter list. All RXSTRING exit subfunction parameters are passed as null-terminated RXSTRINGs. The RXSTRING value can also contain null characters.

For some exit subfunctions, the exit handler can return an RXSTRING character result in the parameter list. The interpreter provides a default 256-byte RXSTRING for the result string. If the result is longer than 256 bytes, a new RXSTRING can be allocated using RexxAllocateMemory(size). The Rexx interpreter returns the RXSTRING storage for the exit handler.

Identifying Exit Handlers to Rexx

System exit handlers must be registered with RexxRegisterExitDll or RexxRegisterExitExe. The system exit handler registration is similar to the subcommand handler registration.

The Rexx system exits are enabled with the RexxStart function parameter Exits. Exits is a pointer to an array of RXSYSEXIT structures. Each RXSYSEXIT structure in the array contains a Rexx exit code and the address of an ASCII exit handler name. The RXENDLST exit code marks the exit list end.

typedef struct {
   const char *    sysexit_name;       /* name of exit handler        */
   int             sysexit_code;       /* system exit function code   */
} RXSYSEXIT;

The Rexx interpreter calls the registered exit handler named in sysexit_name for all of the sysexit_code subfunctions.

Example

...
{
WORKAREARECORD  *user_info[2];         /* saved user information     */
RXSYSEXIT exit_list[2];                /* system exit list           */

  user_info[0] = global_workarea;      /* save global work area for  */
  user_info[1] = NULL;                 /* re-entrance                */

  rc = RexxRegisterExitExe("EditInit", /* register exit handler      */
      &Init_exit,                      /* located at this address    */
      user_info);                      /* save global pointer        */

                                       /* set up for RXINI exit      */
  exit_list[0].sysexit_name = "EditInit";
  exit_list[0].sysexit_code = RXINI;
  exit_list[1].sysexit_code = RXENDLST;

  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    */
                          exit_list,   /* exit list                  */
                          &rc,         /* converted return code      */
                          &retstr);    /* returned result            */

                                       /* process return value       */
...
}

int REXXENTRY Init_exit(
     int   ExitNumber,    /* code defining the exit function    */
     int   Subfunction,   /* code defining the exit subfunction */
     PEXIT ParmBlock)     /* function dependent control block   */
{
  WORKAREARECORD  *user_info[2];       /* saved user information     */
  WORKAREARECORD   global_workarea;    /* application data anchor    */
  unsigned short   query_flag;         /* flag for handler query     */
  rc = RexxQueryExit("EditInit",       /* retrieve application work  */
      NULL,                            /* area anchor from Rexx      */
      &query_flag,
      user_info);

  global_workarea = user_info[0];      /* set the global anchor      */

  if (global_workarea->rexx_trace)     /* trace at start?            */
                                       /* turn on macro tracing      */
    RexxSetTrace(global_workarea->rexx_pid, global_workarea->rexx_tid);
  return RXEXIT_HANDLED;               /* successfully handled       */
}

System Exit Definitions

The Rexx interpreter supports the following system exits:

RXFNC

External function call exit.

RXFNCCAL

Call an external function.

RXCMD

Subcommand call exit.

RXCMDHST

Call a subcommand handler.

RXMSQ

External data queue exit.

RXMSQPLL

Pull a line from the external data queue.

RXMSQPSH

Place a line in the external data queue.

RXMSQSIZ

Return the number of lines in the external data queue.

RXMSQNAM

Set the active external data queue name.

RXSIO

Standard input and output exit.

RXSIOSAY

Write a line to the standard output stream for the SAY instruction.

RXSIOTRC

Write a line to the standard error stream for the Rexx trace or Rexx error messages.

RXSIOTRD

Read a line from the standard input stream for PULL or PARSE PULL.

RXSIODTR

Read a line from the standard input stream for interactive debugging.

RXHLT

Halt processing exit.

RXHLTTST

Test for a HALT condition.

RXHLTCLR

Clear a HALT condition.

RXTRC

External trace exit.

RXTRCTST

Test for an external trace event.

RXINI

Initialization exit.

RXINIEXT

Allow additional Rexx procedure initialization.

RXTER

Termination exit.

RXTEREXT

Process Rexx procedure termination.

The following sections describe each exit subfunction, including:

RXFNC

Processes calls to external functions.

RXFNCCAL

Processes calls to external functions.

  • When called: When Rexx calls an external subroutine or function.

  • Default action: Call the external routine using the usual external function search order.

  • Exit action: Call the external routine, if possible.

  • Continuation: If necessary, raise Rexx error 40 ("Incorrect call to routine"), 43 ("Routine not found"), or 44 ("Function or message did not return data").

  • Parameter list:

    typedef struct {
       struct {
          unsigned rxfferr  : 1;           /* Invalid call to routine.    */
          unsigned rxffnfnd : 1;           /* Function not found.         */
          unsigned rxffsub  : 1;           /* Called as a subroutine if   */
                                           /* TRUE.  Return values are    */
                                           /* optional for subroutines,   */
                                           /* required for functions.     */
       } rxfnc_flags ;
    
       const char *      rxfnc_name;       /* Pointer to function name.   */
       unsigned short    rxfnc_namel;      /* Length of function name.    */
       const char *      rxfnc_que;        /* Current queue name.         */
       unsigned short    rxfnc_quel;       /* Length of queue name.       */
       unsigned short    rxfnc_argc;       /* Number of args in list.     */
       PCONSTRXSTRING    rxfnc_argv;       /* Pointer to argument list.   */
                                           /* List mimics argv list for   */
                                           /* function calls, an array of */
                                           /* RXSTRINGs.                  */
       RXSTRING          rxfnc_retc;       /* Return value.               */
    } RXFNCCAL_PARM;

    The name of the external function is defined by rxfnc_name and rxfnc_namel. The arguments to the function are in rxfnc_argc and rxfnc_argv. If you call the named external function with the Rexx CALL instruction (rather than using a function call), the flag rxffsub is TRUE.

    The exit handler can set rxfnc_flags to indicate whether the external function call was successful. If neither rxfferr nor rxffnfnd is TRUE, the exit handler successfully called the external function. The error flags are checked only when the exit handler handles the request.

    The exit handler sets rxffnfnd to TRUE when the exit handler cannot locate the external function. The interpreter raises Rexx error 43, "Routine not found". The exit handler sets rxfferr to TRUE when the exit handler locates the external function, but the external function returned an error return code. The Rexx interpreter raises error 40, "Incorrect call to routine."

    The exit handler returns the external function result in the rxfnc_retc RXSTRING. The Rexx interpreter raises error 44, "Function or method did not return data," when the external routine is called as a function and the exit handler does not return a result. When the external routine is called with the Rexx CALL instruction, a result is not required.

RXCMD

Processes calls to subcommand handlers.

RXCMDHST

Calls a named subcommand handler.

  • When called: When Rexx procedure issues a command.

  • Default action: Call the named subcommand handler specified by the current Rexx ADDRESS setting.

  • Exit action: Process the call to a named subcommand handler.

  • Continuation: Raise the ERROR or FAILURE condition when indicated by the parameter list flags.

  • Parameter list:

    typedef struct {
       struct {                            /* Condition flags             */
          unsigned rxfcfail : 1;           /* Command failed.  Trap with  */
                                           /* CALL or SIGNAL on FAILURE.  */
          unsigned rxfcerr  : 1;           /* Command ERROR occurred.     */
                                           /* Trap with CALL or SIGNAL on */
                                           /* ERROR.                      */
       } rxcmd_flags;
       const char *      rxcmd_address;    /* Pointer to address name.    */
       unsigned short    rxcmd_addressl;   /* Length of address name.     */
       const char *      rxcmd_dll;        /* dll name for command.       */
       unsigned short    rxcmd_dll_len;    /* Length of dll name.  0 ==>  */
                                           /* executable file.            */
       CONSTRXSTRING     rxcmd_command;    /* The command string.         */
       RXSTRING          rxcmd_retc;       /* Pointer to return code      */
                                           /* buffer.  User allocated.    */
    } RXCMDHST_PARM;

    The rxcmd_command field contains the issued command. Rxcmd_address, rxcmd_addressl, rxcmd_dll, and rxcmd_dll_len fully define the current ADDRESS setting. Rxcmd_retc is an RXSTRING for the return code value assigned to Rexx special variable RC.

    The exit handler can set rxfcfail or rxfcerr to TRUE to raise an ERROR or FAILURE condition.

RXMSQ

External data queue exit.

RXMSQPLL

Pulls a line from the external data queue.

  • When called: When a Rexx PULL instruction, PARSE PULL instruction, or LINEIN built-in function reads a line from the external data queue.

  • Default action: Remove a line from the current Rexx data queue.

  • Exit action: Return a line from the data queue that the exit handler provided.

  • Parameter list:

    typedef struct {
       RXSTRING          rxmsq_retc;       /* Pointer to dequeued entry   */
                                           /* buffer.  User allocated.    */
    } RXMSQPLL_PARM;

    The exit handler returns the queue line in the rxmsq_retc RXSTRING.

RXMSQPSH

Places a line in the external data queue.

  • When called: When a Rexx PUSH instruction, QUEUE instruction, or LINEOUT built-in function adds a line to the data queue.

  • Default action: Add the line to the current Rexx data queue.

  • Exit action: Add the line to the data queue that the exit handler provided.

  • Parameter list:

    typedef struct {
       struct {                            /* Operation flag              */
          unsigned rxfmlifo : 1;           /* Stack entry LIFO when TRUE, */
                                           /* FIFO when FALSE.            */
       } rxmsq_flags;
       CONSTRXSTRING     rxmsq_value;      /* The entry to be pushed.     */
    } RXMSQPSH_PARM;

    The rxmsq_value RXSTRING contains the line added to the queue. It is the responsibility of the exit handler to truncate the string if the exit handler data queue has a maximum length restriction. Rxfmlifo is the stacking order (LIFO or FIFO).

RXMSQSIZ

Returns the number of lines in the external data queue.

  • When called: When the Rexx QUEUED built-in function requests the size of the external data queue.

  • Default action: Request the size of the current Rexx data queue.

  • Exit action: Return the size of the data queue that the exit handler provided.

  • Parameter list:

    typedef struct {
       size_t            rxmsq_size;       /* Number of Lines in Queue    */
    } RXMSQSIZ_PARM;

    The exit handler returns the number of queue lines in rxmsq_size.

RXMSQNAM

Sets the name of the active external data queue.

  • When called: Called by the RXQUEUE("SET", newname) built-in function.

  • Default action: Change the current default queue to newname.

  • Exit action: Change the default queue name for the data queue that the exit handler provided.

  • Parameter list:

    typedef struct {
       CONSTRXSTRING     rxmsq_name;       /* RXSTRING containing         */
                                           /* queue name.                 */
    } RXMSQNAM_PARM;

    rxmsq_name contains the new queue name.

RXSIO

Standard input and output.

Note: The PARSE LINEIN instruction and the LINEIN, LINEOUT, LINES, CHARIN, CHAROUT, and CHARS built-in functions do not call the RXSIO exit handler.

RXSIOSAY

Writes a line to the standard output stream.

  • When called: When the SAY instruction writes a line to the standard output stream.

  • Default action: Write a line to the standard output stream (STDOUT).

  • Exit action: Write a line to the output stream that the exit handler provided.

  • Parameter list:

    typedef struct {
       CONSTRXSTRING      rxsio_string;     /* String to display.          */
    } RXSIOSAY_PARM;

    The output line is contained in rxsio_string. The output line can be of any length. It is the responsibility of the exit handler to truncate or split the line if necessary.

RXSIOTRC

Writes trace and error message output to the standard error stream.

  • When called: To output lines of trace output and Rexx error messages.

  • Default action: Write a line to the standard error stream (.ERROR).

  • Exit action: Write a line to the error output stream that the exit handler provided.

  • Parameter list:

    typedef struct {
       CONSTRXSTRING       rxsio_string;     /* Trace line to display.      */
    } RXSIOTRC_PARM;

    The output line is contained in rxsio_string. The output line can be of any length. It is the responsibility of the exit handler to truncate or split the line if necessary.

RXSIOTRD

Reads from standard input stream.

  • When called: To read from the standard input stream for the Rexx PULL and PARSE PULL instructions.

  • Default action: Read a line from the standard input stream (STDIN).

  • Exit action: Return a line from the standard input stream that the exit handler provided.

  • Parameter list:

    typedef struct {
       RXSTRING          rxsiotrd_retc;    /* RXSTRING for input.         */
    } RXSIOTRD_PARM;

    The input stream line is returned in the rxsiotrd_retc RXSTRING.

RXSIODTR

Interactive debug input.

  • When called: To read from the debug input stream for interactive debug prompts.

  • Default action: Read a line from the standard input stream (STDIN).

  • Exit action: Return a line from the standard debug stream that the exit handler provided.

  • Parameter list:

    typedef struct {
       RXSTRING          rxsiodtr_retc;    /* RXSTRING for input.         */
    } RXSIODTR_PARM;

    The input stream line is returned in the rxsiodtr_retc RXSTRING.

RXHLT

HALT condition processing.

Because the RXHLT exit handler is called after every Rexx instruction, enabling this exit slows Rexx program execution. The RexxSetHalt function can halt a Rexx program without between-instruction polling.

RXHLTTST

Tests the HALT indicator.

  • When called: When the interpreter polls externally raises HALT conditions. The exit will be called after completion of every Rexx instruction.

  • Default action: The interpreter uses the system facilities for trapping Cntrl-Break signals.

  • Exit action: Return the current state of the HALT condition (either TRUE or FALSE).

  • Continuation: Raise the Rexx HALT condition if the exit handler returns TRUE.

  • Parameter list:

    typedef struct {
       struct {                            /* Halt flag                   */
          unsigned rxfhhalt : 1;           /* Set if HALT occurred.       */
       } rxhlt_flags;
    } RXHLTTST_PARM;

    If the exit handler sets rxfhhalt to TRUE, the HALT condition is raised in the Rexx program.

    The Rexx program can retrieve the reason string using the CONDITION("D") built-in function.

RXHLTCLR

Clears the HALT condition.

  • When called: When the interpreter has recognized and raised a HALT condition, to acknowledge processing of the HALT condition.

  • Default action: The interpreter resets the Cntrl-Break signal handlers.

  • Exit action: Reset exit handler HALT state to FALSE.

  • Parameters: None.

RXTRC

Tests the external trace indicator.

Note: Because the RXTRC exit is called after every Rexx instruction, enabling this exit slows Rexx procedure execution. The RexxSetTrace function can turn on Rexx tracing without the between-instruction polling.

RXTRCTST

Tests the external trace indicator.

  • When called: When the interpreter polls for an external trace event. The exit is called after completion of every Rexx instruction.

  • Default action: None.

  • Exit action: Return the current state of external tracing (either TRUE or FALSE).

  • Continuation: When the exit handler switches from FALSE to TRUE, the Rexx interpreter enters the interactive Rexx debug mode using TRACE ?R level of tracing. When the exit handler switches from TRUE to FALSE, the Rexx interpreter exits the interactive debug mode.

  • Parameter list:

    typedef struct {
       struct {
          unsigned rxftrace : 1;        /* External trace setting        */
       } rxtrc_flags;
    } RXTRCTST_PARM;

    If the exit handler switches rxftrace to TRUE, Rexx switches on the interactive debug mode. If the exit handler switches rxftrace to FALSE, Rexx switches off the interactive debug mode.

RXINI

Initialization processing. This exit is called as the last step of Rexx program initialization.

RXINIEXT

Initialization exit.

  • When called: Before the first instruction of the Rexx procedure is interpreted.

  • Default action: None.

  • Exit action: The exit handler can perform additional initialization. For example:

    • Use RexxVariablePool to initialize application-specific variables.

    • Use RexxSetTrace to switch on the interactive Rexx debug mode.

  • Parameters: None.

RXTER

Termination processing.

The RXTER exit is called as the first step of Rexx program termination.

RXTEREXT

Termination exit.

  • When called: After the last instruction of the Rexx procedure has been interpreted.

  • Default action: None.

  • Exit action: The exit handler can perform additional termination activities. For example, the exit handler can use RexxVariablePool to retrieve the Rexx variable values.

  • Parameters: None.

System Exit Interface Functions

The system exit functions are similar to the subcommand handler functions. The system exit functions are:

RexxRegisterExitDll

RexxRegisterExitDll registers an exit handler that resides in a dynamic-link library routine.

retc = RexxRegisterExitDll(ExitName, ModuleName, EntryPoint,
                           UserArea, DropAuth);

Parameters

ExitName (const char *) - input

is the address of an ASCII exit handler name.

ModuleName (const char *) - input

is the address of an ASCII dynamic-link library name. ModuleName is the DLL file containing the exit handler routine.

EntryPoint (const char *) - input

is the address of an ASCII dynamic-link procedure name. EntryPoint is the routine within ModuleName that Rexx calls as an exit handler.

UserArea (const char *) - input

is the address of an area of user-defined information. The user-defined information is a buffer the size of two pointer values. The bytes UserArea buffer is saved with the subcommand handler registration. UserArea can be null if there is no user information to be saved. The RexxQueryExit function can retrieve the saved user information.

DropAuth (size_t) - input

is the drop authority. DropAuth identifies the processes that can deregister the exit handler. Possible DropAuth values are:

RXEXIT_DROPPABLE

Any process can deregister the exit handler with RexxDeregisterExit.

RXEXIT_NONDROP

Only a thread within the same process as the thread that registered the handler can deregister the handler with RexxDeregisterExit.

Return Codes

RXEXIT_OK 0The system exit function executed successfully.
RXEXIT_DUP 10A duplicate handler name has been successfully registered. There is either an executable handler with the same name registered in another process, or a DLL handler with the same name registered in another DLL. (To address this exit handler, you must specify its library name.)
RXEXIT_NOEMEM 1002There is insufficient memory available to complete this request.

RexxRegisterExitExe

RexxRegisterExitExe registers an exit handler that resides within the application code.

retc = RexxRegisterExitExe(ExitName, EntryPoint, UserArea);

Parameters

ExitName (const char *) - input

is the address of an ASCII exit handler name.

EntryPoint (REXXPFN) - input

is the address of the exit handler entry point within the application executable file.

UserArea (const char *) - input

is the address of an area of user-defined information. The user-defined information is a buffer the size of two pointer values. The bytes UserArea buffer is saved with the subcommand handler registration. UserArea can be null if there is no user information to be saved. The RexxQueryExit function can retrieve the user information.

Return Codes

RXEXIT_OK 0The system exit function executed successfully.
RXEXIT_DUP 10A duplicate handler name has been successfully registered. There is either an executable handler with the same name registered in another process, or a DLL handler with the same name registered in another DLL. (To address this exit handler, you must specify its library name.)
RXEXIT_NOTREG 30Registration was unsuccessful due to duplicate handler and DLL names (RexxRegisterExitExe or RexxRegisterExitDll); the exit handler is not registered (other Rexx exit handler functions).
RXEXIT_NOEMEM 1002There is insufficient memory available to complete this request.

Remarks

If ExitName has the same name as a handler registered with RexxRegisterExitDll, RexxRegisterExitExe returns RXEXIT_DUP, which means that the new exit handler has been properly registered.

Example

WORKAREARECORD  *user_info[2];       /* saved user information     */

user_info[0] = global_workarea;      /* save global work area for  */
user_info[1] = NULL;                 /* re-entrance                */

rc = RexxRegisterExitExe("IO_Exit",  /* register editor handler    */
    &Edit_IO_Exit,                   /* located at this address    */
    user_info);                      /* save global pointer        */

RexxDeregisterExit

RexxDeregisterExit deregisters an exit handler.

retc = RexxDeregisterExit(ExitName, ModuleName);

Parameters

ExitName (const char *) - input

is the address of an ASCII exit handler name.

ModuleName (const char *) - input

is the address of an ASCII dynamic-link library name. ModuleName restricts the query to an exit handler within the ModuleName library. When ModuleName is null, RexxDeregisterExit searches the RexxRegisterExitExe exit handler list for a handler within the current process. If RexxDeregisterExit does not find a RexxRegisterExitExe handler, it searches the RexxRegisterExitDll exit handler list.

Return Codes

RXEXIT_OK 0The system exit function executed successfully.
RXEXIT_NOTREG 30Registration was unsuccessful due to duplicate handler and DLL names (RexxRegisterExitExe or RexxRegisterExitDll); the exit handler is not registered (other Rexx exit handler functions).
RXEXIT_NOCANDROP 40The exit handler has been registered as "not droppable."

Remarks

The handler is removed from the exit handler list.

RexxQueryExit

RexxQueryExit queries an exit handler and retrieves saved user information.

retc = RexxQueryExit(ExitName, ModuleName, Flag, UserWord);

Parameters

ExitName (const char *) - input

is the address of an ASCII exit handler name.

ModuleName (const char *) - input

restricts the query to an exit handler within the ModuleName dynamic-link library. When ModuleName is null, RexxQueryExit searches the RexxRegisterExitExe exit handler list for a handler within the current process. If RexxQueryExit does not find a RexxRegisterExitExe handler, it searches the RexxRegisterExitDll exit handler list.

Flag (unsigned short *) - output

is the ExitName exit handler registration status. When RexxQueryExit returns RXEXIT_OK, the ExitName exit handler is currently registered. When RexxQueryExit returns RXEXIT_NOTREG, the ExitName exit handler is not registered.

UserWord (char *( - output

is the address of an area to receive the user information saved with RexxRegisterExitExe or RexxRegisterExitDll. The referenced area must be large enough to store two pointer values. UserWord can be null if the saved user information is not required.

Return Codes

RXEXIT_OK 0The system exit function executed successfully.
RXEXIT_NOTREG 30Registration was unsuccessful due to duplicate handler and DLL names (RexxRegisterExitExe or RexxRegisterExitDll); the exit handler is not registered (other Rexx exit handler functions).

Example

int REXXENTRY Edit_IO_Exit(
  int       Code,       /* Major exit code                          */
  int       SubCode     /* Minor exit code                          */
  PEXIT     Parms)      /* Exit-specific parameters                 */
{
  WORKAREARECORD  *user_info[2];       /* saved user information     */
  WORKAREARECORD   global_workarea;    /* application data anchor    */
  unsigned short   query_flag;         /* flag for handler query     */


  rc = RexxQueryExit("IO_Exit",        /* retrieve application work  */
      NULL,                            /* area anchor from Rexx.     */
      &query_flag,
      user_info);

  global_workarea = user_info[0];      /* set the global anchor      */
...
}