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:
The administration of resources at the beginning and the end of interpretation
Linkages to external functions and subcommand handlers
Special language features; for example, input and output to standard resources
Polling for halt and external trace events
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.
The following is a sample exit handler definition:
LONG APIENTRY Rexx_IO_exit( LONG ExitNumber, /* code defining the exit function */ LONG Subfunction, /* code defining the exit subfunction */ PEXIT ParmBlock); /* function-dependent control block */
where:
is the major function code defining the type of exit call.
is the subfunction code defining the exit event for the call.
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 handlers return an integer value that signals one of the following actions:
The exit handler processed the exit subfunction and updated the subfunction parameter list as required. The Rexx interpreter continues with processing as usual.
The exit handler did not process the exit subfunction. The Rexx interpreter processes the subfunction as if the exit handler were not called.
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".
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 GlobalAlloc(size). The Rexx interpreter returns the RXSTRING storage for the exit handler.
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 { PSZ sysexit_name; /* name of exit handler */ LONG 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.
... { 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 */ ... } LONG APIENTRY Init_exit( LONG ExitNumber, /* code defining the exit function */ LONG 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 */ USHORT 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 */ }
The Rexx interpreter supports the following system exits:
External function call exit.
Call an external function.
Subcommand call exit.
Call a subcommand handler.
External data queue exit.
Pull a line from the external data queue.
Place a line in the external data queue.
Return the number of lines in the external data queue.
Set the active external data queue name.
Standard input and output exit.
Write a line to the standard output stream for the SAY instruction.
Write a line to the standard error stream for the Rexx trace or Rexx error messages.
Read a line from the standard input stream for PULL or PARSE PULL.
Read a line from the standard input stream for interactive debugging.
Halt processing exit.
Test for a HALT condition.
Clear a HALT condition.
External trace exit.
Test for an external trace event.
Initialization exit.
Allow additional Rexx procedure initialization.
Termination exit.
Process Rexx procedure termination.
The following sections describe each exit subfunction, including:
The service the subfunction provides
When Rexx calls the exit handler
The default action when the exit is not provided or the exit handler does not process the subfunction
The exit action
The subfunction parameter list
The state of the variable pool interface during the exit handler call (the variable pool interface is fully enabled for the RXCMD, RXFNC, RXINI, RXTER, RXHLT, RXCMD, RXFNC, RXSIO, and RXMSQ exit handler calls.
Processes calls to external functions.
Note: The variable pool interface is fully enabled during calls to the RXFNC exit handler.
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 ; PUCHAR rxfnc_name; /* Pointer to function name. */ USHORT rxfnc_namel; /* Length of function name. */ PUCHAR rxfnc_que; /* Current queue name. */ USHORT rxfnc_quel; /* Length of queue name. */ USHORT rxfnc_argc; /* Number of args in list. */ PRXSTRING 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.
Processes calls to subcommand handlers.
Note: The variable pool interface function is fully enabled during calls to the RXCMD exit handlers.
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; PUCHAR rxcmd_address; /* Pointer to address name. */ USHORT rxcmd_addressl; /* Length of address name. */ PUCHAR rxcmd_dll; /* dll name for command. */ USHORT rxcmd_dll_len; /* Length of dll name. 0 ==> */ /* executable file. */ RXSTRING 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.
External data queue exit.
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.
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; RXSTRING 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).
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 { ULONG rxmsq_size; /* Number of Lines in Queue */ } RXMSQSIZ_PARM;
The exit handler returns the number of queue lines in rxmsq_size.
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 { RXSTRING rxmsq_name; /* RXSTRING containing */ /* queue name. */ } RXMSQNAM_PARM;
rxmsq_name contains the new queue name.
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.
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 { RXSTRING 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.
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 { RXSTRING 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.
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 output. */ } RXSIOTRD_PARM;
The input stream line is returned in the rxsiotrd_retc RXSTRING.
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 output. */ } RXSIODTR_PARM;
The input stream line is returned in the rxsiodtr_retc RXSTRING.
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.
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.
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.
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.
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.
Initialization processing. This exit is called as the last step of Rexx program initialization.
Note: The variable pool interface is fully enabled for this exit.
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.
Termination processing.
The RXTER exit is called as the first step of Rexx program termination.
Note: The variable pool interface is fully enabled for this exit.
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.
The system exit functions are similar to the subcommand handler functions. The system exit functions are:
RexxRegisterExitDll registers an exit handler that resides in a dynamic-link library routine.
retc = RexxRegisterExitDll(ExitName, ModuleName, EntryPoint, UserArea, DropAuth);
is the address of an ASCII exit handler name.
is the address of an ASCII dynamic-link library name. ModuleName is the DLL file containing the exit handler routine.
is the address of an ASCII dynamic-link procedure name. EntryPoint is the routine within ModuleName that Rexx calls as an exit handler.
is the address of an 8-byte area of user-defined information. The 8 bytes UserArea addresses are saved with the exit handler registration. UserArea can be null if there is no user information to be saved. The RexxQueryExit function can retrieve the saved user information.
is the drop authority. DropAuth identifies the processes that can deregister the exit handler. Possible DropAuth values are:
Any process can deregister the exit handler with RexxDeregisterExit.
Only a thread within the same process as the thread that registered the handler can deregister the handler with RexxDeregisterExit.
RXEXIT_OK | 0 | The system exit function executed successfully. |
RXEXIT_DUP | 10 | A 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 | 1002 | There is insufficient memory available to complete this request. |
EntryPoint can be only a 32-bit routine.
RexxRegisterExitExe registers an exit handler that resides within the application code.
retc = RexxRegisterExitExe(ExitName, EntryPoint, UserArea);
is the address of an ASCII exit handler name.
is the address of the exit handler entry point within the application executable file.
is the address of an 8-byte area of user-defined information. The 8 bytes UserArea addresses are saved with the exit handler registration. UserArea can be null if there is no user information to be saved. The RexxQueryExit function can retrieve the user information.
RXEXIT_OK | 0 | The system exit function executed successfully. |
RXEXIT_DUP | 10 | A 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 | 30 | Registration 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 | 1002 | There is insufficient memory available to complete this request. |
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.
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 deregisters an exit handler.
retc = RexxDeregisterExit(ExitName, ModuleName);
is the address of an ASCII exit handler name.
is the address of an ASCII dynamic-link library name. ModuleName restricts the query to an exit handler within the ModuleName dynamic-link 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.
RXEXIT_OK | 0 | The system exit function executed successfully. |
RXEXIT_NOTREG | 30 | Registration 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 | 40 | The exit handler has been registered as "not droppable." |
The handler is removed from the exit handler list.
RexxQueryExit queries an exit handler and retrieves saved user information.
retc = RexxQueryExit(ExitName, ModuleName, Flag, UserWord);
is the address of an ASCII exit handler name.
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.
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.
is the address of an 8-byte area to receive the user information saved with RexxRegisterExitExe or RexxRegisterExitDll. UserWord can be null if the saved user information is not required.
ULONG APIENTRY Edit_IO_Exit( PRXSTRING Command, /* Command string passed from the caller */ PUSHORT Flags, /* pointer too short for return of flags */ PRXSTRING Retstr) /* pointer to RXSTRING for RC return */ { WORKAREARECORD *user_info[2]; /* saved user information */ WORKAREARECORD global_workarea; /* application data anchor */ USHORT 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 */ ... }