Jump to content

REXX.LIB

From EDM2

REXX.LIB is the import library for the IBM SAA REXX interpreter and its external programming interface, distributed with the IBM OS/2 Developer's Toolkit. It provides linker stubs for the full REXX External Application Interface: starting the REXX interpreter from C/C++ code, accessing REXX variables, registering external functions and subcommand handlers, installing system exit handlers, managing named queues, and controlling the REXX Macro Space.

File size in the OS/2 Warp 4.52 Toolkit 4.5: 9,216 bytes (2001-04-09). Source DLLs: REXX.DLL (interpreter entry point), REXXSAA.DLL, REXXAPI.DLL (external API services). Copyright: IBM Corporation 1989–1991.

Naming Conventions

The REXX External API provides every function under three equivalent names:

Style Example Notes
Mixed-case (Rexx*) RexxStart Primary 32-bit SAA API name. Used in new code.
Uppercase macro (REXX*) REXXSTART #define REXXSTART RexxStart — uppercase alias defined in rexxsaa.h. Provided for case-insensitive language environments.
Legacy (RX*) RXFUNCTIONREGISTER Older naming style from early 16-bit OS/2 REXX; still exported for backward compatibility.

All three resolve to the same DLL export. New code should use the mixed-case Rexx* names.

Include Files

Header Guard macro Contents
rexxsaa.h INCL_REXXSAA Entire REXX SAA API. Alternatively include individual subsections with more specific macros (see below).
— INCL_RXSUBCOM Subcommand handler registration; RXSUBCOM_* constants; RexxSubcomHandler callback typedef
— INCL_RXSHV Shared variable pool; RXSHV_* function codes and return flags; SHVBLOCK structure
— INCL_RXFUNC External function registration; RXFUNC_* constants; RexxFunctionHandler callback typedef
— INCL_RXSYSEXIT System exit registration; all RXFNC/RXCMD/RXMSQ/RXSIO/RXHLT/RXTRC/RXINI/RXTER exit codes and parameter structures
— INCL_RXMACRO Macro Space management; RXMACRO_* constants
— INCL_RXARI Asynchronous Halt/Trace interface; RXARI_* constants

Core Types

RXSTRING

The fundamental data type for all REXX string values exchanged between C code and the REXX interpreter:

typedef struct _RXSTRING {
    ULONG  strlength;    /* length of string (not null-terminated) */
    PCH    strptr;       /* pointer to string data */
} RXSTRING;

REXX strings are not null-terminated; length is carried separately. Convenience macros:

Macro Usage
MAKERXSTRING(r, p, l) Initialize an RXSTRING: sets strptr=p, strlength=l
RXNULLSTRING(r) True if strptr is NULL (uninitialized)
RXZEROLENSTRING(r) True if pointer is non-NULL but length is 0 (empty string)
RXVALIDSTRING(r) True if pointer is non-NULL and length is non-zero
RXSTRLEN(r) Length of string (0 if null string)
RXSTRPTR(r) Raw pointer to string data

RXAUTOBUFLEN (256) is the conventional initial size to allocate for an RXSTRING return buffer before calling REXX; REXX enlarges it if needed (using DosAllocMem) and always frees caller-allocated storage if it replaces it.

RXSYSEXIT

Specifies one system exit handler in the array passed to RexxStart:

typedef struct _RXSYSEXIT {
    PSZ   sysexit_name;   /* name of the registered exit handler */
    LONG  sysexit_code;   /* exit function to call this handler for */
} RXSYSEXIT;

The array is terminated by an entry with sysexit_code = RXENDLST (0).

SHVBLOCK

Request block for the Variable Pool interface. Multiple requests can be chained via shvnext:

typedef struct _SHVBLOCK {
    struct _SHVBLOCK *shvnext;      /* next block in chain, or NULL */
    RXSTRING          shvname;      /* variable name */
    RXSTRING          shvvalue;     /* variable value (in/out) */
    ULONG             shvnamelen;   /* length of name */
    ULONG             shvvaluelen;  /* length of fetched value */
    UCHAR             shvcode;      /* operation code (RXSHV_*) */
    UCHAR             shvret;       /* per-block return flags */
} SHVBLOCK;

API Groups

Interpreter Startup

RexxStart(argc, argv, progname, instore, envname, calltype, exits, retcode, result)
Invokes the REXX interpreter to run a REXX program. The program is either a file on disk or an in-memory image (instore):
Parameter Type Description
argc LONG Number of arguments to pass to the REXX program (0 = no arguments)
argv PRXSTRING Array of argc RXSTRING argument values. Becomes the REXX variable ARG(1), ARG(2), etc.
progname PSZ Path to the REXX source file (e.g. "C:\\UTILS\\BACKUP.CMD"). May include drive and extension.
instore PRXSTRING Two-element array: instore[0] = REXX source in memory (or NULL to read from file); instore[1] = tokenized image (output on first run; input on subsequent runs for speed). Pass NULL to use only the file.
envname PSZ Initial environment name for ADDRESS instruction (e.g. "CMD", "PMREXX"). NULL = default ("CMD").
calltype LONG How the program is invoked: RXCOMMAND (0), RXSUBROUTINE (1), RXFUNCTION (2).
exits PRXSYSEXIT Array of RXSYSEXIT structures listing exit handlers to install, terminated by RXENDLST. NULL = no exits.
retcode PSHORT Receives the numeric return value if the REXX program's RETURN/EXIT value is a valid integer.
result PRXSTRING Receives the string return value from the REXX program's RETURN or EXIT instruction.

Returns 0 on normal completion, or a negative error code if the interpreter itself failed to start.

Call type constants

Constant Value Behavior
RXCOMMAND 0 Program is an OS/2 command (run from command prompt). REXX sets RC from the return value; only ARG(1) is a single command string.
RXSUBROUTINE 1 Program is a called subroutine. Return value is available but not required.
RXFUNCTION 2 Program is a function. Return value is required; error if RETURN omits a value.

Shared Variable Pool

External functions and exit handlers exchange data with the running REXX program by calling RexxVariablePool from within a callback. It is only valid during a callback invoked by the interpreter.

RexxVariablePool(pSHVBlock)
Processes a chain of SHVBLOCK requests. Returns RXSHV_NOAVL (144) if called outside an active REXX callback.

Operation codes (shvcode)

Code Value Operation
RXSHV_SET 0x00 Set a variable to the value in shvvalue. Variable name in shvname must be uppercase.
RXSHV_FETCH 0x01 Fetch the value of a variable into shvvalue. If shvvalue.strptr is NULL, REXX allocates a buffer; caller must free with DosFreeMem.
RXSHV_DROPV 0x02 Drop (undefine) a variable.
RXSHV_SYSET 0x03 Symbolic set: shvname is evaluated as a REXX expression to find the target variable name, then set.
RXSHV_SYFET 0x04 Symbolic fetch.
RXSHV_SYDRO 0x05 Symbolic drop.
RXSHV_NEXTV 0x06 Fetch the "next" variable in sequence. Iterating with NEXTV until RXSHV_LVAR is set enumerates all currently defined variables.
RXSHV_PRIV 0x07 Fetch private REXX information (version, source name, etc.).
RXSHV_EXIT 0x08 Set the REXX function exit value (return value for the function call from an exit handler).

Return flags (shvret)

Flag Value Meaning
RXSHV_OK 0x00 Operation succeeded
RXSHV_NEWV 0x01 Variable did not exist (fetch returned its name as value)
RXSHV_LVAR 0x02 This was the last variable in the NEXTV enumeration
RXSHV_TRUNC 0x04 Value was truncated (fetch buffer too small)
RXSHV_BADN 0x08 Invalid variable name
RXSHV_MEMFL 0x10 Memory allocation failure
RXSHV_BADF 0x80 Invalid function code in shvcode

External Functions

External functions extend REXX by calling C/C++ code when the REXX program calls an unknown function name. Registered functions are stored in the Available Function Table (AFT), a process-wide registry maintained by REXXAPI.DLL.

Callback signature

ULONG APIENTRY MyFunc(PUCHAR funcname,   /* function name called */
                      ULONG  argc,       /* argument count */
                      PRXSTRING argv,    /* argument array */
                      PSZ    queuename,  /* current REXX queue name */
                      PRXSTRING result); /* return value (fill this in) */

Return 0 if the function handled the call. Any non-zero return causes REXX to raise an error.

RexxRegisterFunctionDll(funcname, dllname, entryname)
Registers a function implemented in a DLL. funcname is the REXX name (case-insensitive); dllname is the DLL file name without path or extension; entryname is the exported function name in that DLL.
RexxRegisterFunctionExe(funcname, entrypoint)
Registers a function whose entry point is already loaded in the current process (e.g. a static function in an EXE). entrypoint is a PFN (function pointer).
RexxDeregisterFunction(funcname)
Removes a function from the AFT.
RexxQueryFunction(funcname)
Returns RXFUNC_OK (0) if the function is registered, RXFUNC_NOTREG (30) if not.
RexxCallFunction(funcname, argc, argv, queuename, result)
Directly invokes a registered external function from C code (without starting a REXX interpreter). Useful for testing registered functions or calling them from non-REXX contexts.

Error codes

Constant Value Meaning
RXFUNC_OK 0 Success
RXFUNC_DEFINED 10 Function already registered (registration still succeeds)
RXFUNC_NOMEM 20 Insufficient memory
RXFUNC_NOTREG 30 Function not registered
RXFUNC_MODNOTFND 40 DLL module not found
RXFUNC_ENTNOTFND 50 Entry point not found in DLL
RXFUNC_NOTINIT 60 REXX API not initialized
RXFUNC_BADTYPE 70 Invalid registration type

Subcommand Handlers

A subcommand handler processes commands issued by the REXX ADDRESS envname "command" statement. REXX calls the registered handler with the command string and receives a return code.

Callback signature

ULONG APIENTRY MySubcom(PRXSTRING command,   /* the command string */
                        PUSHORT   flags,      /* RXSUBCOM_ERROR / _FAILURE */
                        PRXSTRING result);    /* return value to REXX RC */

Set *flags to RXSUBCOM_ERROR (0x01) to make REXX raise the REXX ERROR condition, or RXSUBCOM_FAILURE (0x02) for FAILURE. Put the numeric return code string in result.

RexxRegisterSubcomDll(envname, dllname, entryname, userarea, authority)
Registers a subcommand handler in a DLL. authority: RXSUBCOM_DROPPABLE (0) = any process can drop it; RXSUBCOM_NONDROP (1) = only the registering process can drop it.
RexxRegisterSubcomExe(envname, entrypoint, userarea)
Registers a subcommand handler at an in-process address.
RexxDeregisterSubcom(envname, dllname)
Removes a subcommand handler registration.
RexxQuerySubcom(envname, dllname, pExists, puserarea)
Queries whether a subcommand environment is registered. Sets *pExists to RXSUBCOM_ISREG (1) if found.
RexxLoadSubcom(envname, dllname)
Forces the DLL containing a subcommand handler to be loaded into memory without executing a subcommand. Useful for pre-loading handlers at application startup.

Error codes

Constant Value Meaning
RXSUBCOM_OK 0 Success
RXSUBCOM_DUP 10 Duplicate name (registered anyway)
RXSUBCOM_MAXREG 20 Maximum registrations reached
RXSUBCOM_NOTREG 30 Environment not registered
RXSUBCOM_NOCANDROP 40 Environment is NONDROP
RXSUBCOM_LOADERR 50 Could not load DLL
RXSUBCOM_NOPROC 127 Entry point not found in DLL

System Exit Handlers

System exits allow C code to intercept and override specific REXX interpreter activities: I/O operations, external function calls, queue access, halt/trace testing, and initialization/termination.

Callback signature

LONG APIENTRY MyExit(LONG exitcode,    /* RXFNC, RXCMD, RXSIO, etc. */
                     LONG subcode,     /* subfunction (RXFNCCAL, etc.)*/
                     PEXIT pblock);    /* pointer to parameter block  */

Return RXEXIT_HANDLED (0) to indicate the exit handled the event (REXX uses the result from the parameter block). Return RXEXIT_NOT_HANDLED (1) to pass control back to REXX's default behavior.

Exit codes and subfunctions

Exit Code Subfunction Description
RXFNC 2 RXFNCCAL (1) External function call — intercept calls to external functions; RXFNCCAL_PARM block
RXCMD 3 RXCMDHST (1) Host (subcommand) command — intercept ADDRESS commands; RXCMDHST_PARM block
RXMSQ 4 RXMSQPLL (1) Pull a line from the queue; RXMSQPLL_PARM block
RXMSQ 4 RXMSQPSH (2) Push a line onto the queue; RXMSQPSH_PARM block (with LIFO flag)
RXMSQ 4 RXMSQSIZ (3) Return the queue size; RXMSQSIZ_PARM block
RXMSQ 4 RXMSQNAM (20) Set the active queue name; RXMSQNAM_PARM block
RXSIO 5 RXSIOSAY (1) SAY output — intercept REXX SAY output; RXSIOSAY_PARM block (redirect to PM window, file, etc.)
RXSIO 5 RXSIOTRC (2) Trace output; RXSIOTRC_PARM block
RXSIO 5 RXSIOTRD (3) Read from character stream (PULL from stdin); RXSIOTRD_PARM block
RXSIO 5 RXSIODTR (4) Debug read from character stream; RXSIODTR_PARM block
RXHLT 7 RXHLTCLR (1) Clear HALT indicator; RXHLTTST_PARM
RXHLT 7 RXHLTTST (2) Test HALT indicator; set rxhlt_flags.rxfhhalt=1 to trigger HALT
RXTRC 8 RXTRCTST (1) Test external trace; set rxtrc_flags.rxftrace=1 to enable trace
RXINI 9 RXINIEXT (1) Interpreter initialization (called once at startup)
RXTER 10 RXTEREXT (1) Interpreter termination (called once at exit)
RexxRegisterExitDll(exitname, dllname, entryname, userarea, authority)
Registers an exit handler in a DLL.
RexxRegisterExitExe(exitname, entrypoint, userarea)
Registers an exit handler at an in-process address.
RexxDeregisterExit(exitname, dllname)
Removes an exit handler.
RexxQueryExit(exitname, dllname, pExists, puserarea)
Queries whether an exit handler is registered.

Queue Management

REXX queues (the REXX data stack) allow programs and external code to pass strings between REXX programs and C programs. Each queue is identified by a name; the default queue is named SESSION.

RexxCreateQueue(buf, buflen, reqname, dupflag)
Creates a new named queue. If reqname is NULL or empty, a unique name is generated and returned in buf. dupflag receives 1 if the name already existed but the call succeeded anyway.
RexxDeleteQueue(queuename)
Deletes a named queue and discards all entries.
RexxAddQueue(queuename, entry, lifo)
Adds a string to a queue. lifo=RXQUEUE_LIFO (1) pushes to the top (stack); lifo=RXQUEUE_FIFO (0) appends to the end (queue).
RexxPullQueue(queuename, entry, timestamp, wait)
Removes and returns the top entry from a queue. entry is filled with the dequeued string (caller must free). wait=RXQUEUE_WAIT (1) blocks until an entry is available; RXQUEUE_NOWAIT (0) returns immediately.
RexxQueryQueue(queuename, pcount)
Returns the number of entries currently in the named queue via *pcount.

Asynchronous Halt/Trace Control

These functions allow one thread (or process) to request that a running REXX program halt or start tracing. They operate on any REXX program running in the specified process/thread.

RexxSetHalt(pid, tid)
Requests that the REXX program running in process pid, thread tid raise a HALT condition at the next statement boundary. The REXX program's HALT condition handler is invoked, or the program terminates if none is installed.
RexxSetTrace(pid, tid)
Requests that the REXX program running in process pid, thread tid enable interactive trace mode (equivalent to TRACE I).
RexxResetTrace(pid, tid)
Turns off external trace mode for the specified REXX program.

Return codes

Constant Value Meaning
RXARI_OK 0 Request delivered successfully
RXARI_NOT_FOUND 1 No REXX program running in the specified process/thread
RXARI_PROCESSING_ERROR 2 Internal error delivering the request

Macro Space

The REXX Macro Space is a per-process in-memory library of pre-tokenized REXX functions. Macro space functions are resolved before external function calls and disk file searches, making them significantly faster to call than file-based REXX subroutines.

RexxAddMacro(funcname, filename, searchpos)
Reads and tokenizes the REXX source file filename and stores it in the Macro Space under the name funcname. searchpos: RXMACRO_SEARCH_BEFORE (1) = this macro is checked before external functions in the AFT; RXMACRO_SEARCH_AFTER (2) = checked after AFT.
RexxDropMacro(funcname)
Removes a single function from the Macro Space.
RexxClearMacroSpace()
Removes all functions from the Macro Space.
RexxSaveMacroSpace(count, funcnames, filename)
Saves Macro Space functions to a binary file. count=0 saves all functions; otherwise funcnames is an array of count names to save.
RexxLoadMacroSpace(count, funcnames, filename)
Loads previously saved Macro Space functions from a binary file. count=0 loads all; otherwise loads only the named functions from the file.
RexxQueryMacro(funcname, pposition)
Queries whether a function is in the Macro Space. Sets *pposition to RXMACRO_SEARCH_BEFORE or RXMACRO_SEARCH_AFTER if found. Returns RXMACRO_OK or RXMACRO_NOT_FOUND.
RexxReorderMacro(funcname, newposition)
Changes a macro's search-order position.
RexxExecuteMacroFunction(funcname, argc, argv, queuename, result)
Directly executes a function from the Macro Space without starting a full REXX interpreter session. Equivalent to calling a REXX function by name.

Macro Space error codes

Constant Value Meaning
RXMACRO_OK 0 Success
RXMACRO_NO_STORAGE 1 Insufficient storage
RXMACRO_NOT_FOUND 2 Function not in Macro Space
RXMACRO_EXTENSION_REQUIRED 3 File must have .CMD extension for save
RXMACRO_ALREADY_EXISTS 4 Function already in Macro Space
RXMACRO_FILE_ERROR 5 File I/O error during save or load
RXMACRO_SIGNATURE_ERROR 6 Macro Space file format invalid
RXMACRO_SOURCE_NOT_FOUND 7 Source file not found
RXMACRO_INVALID_POSITION 8 Invalid search order position value
RXMACRO_NOT_INIT 9 API not initialized

Usage

Build Instructions

IBM VisualAge C++ / ILINK

icc -O2 -Gm -c myapp.c
ilink /PM:VIO myapp.obj os2386.lib rexx.lib

OpenWatcom

wcl386 -bt=os2 -mf -c myapp.c
wlink system os2v2 file myapp.obj library os2386.lib library rexx.lib

EMX/GCC

gcc -Zomf -c myapp.c
gcc -Zomf -o myapp.exe myapp.o -los2386 -lrexx

Running a REXX script from C

#define INCL_REXXSAA
#include <rexxsaa.h>
#include <stdio.h>

int main(void)
{
    RXSTRING args[1];
    RXSTRING result;
    SHORT    retcode = 0;
    CHAR     resbuf[256];

    /* Pass one argument: "Hello from C" */
    MAKERXSTRING(args[0], "Hello from C", 12);

    /* Result buffer: pre-allocate; REXX may reallocate */
    MAKERXSTRING(result, resbuf, sizeof(resbuf));

    LONG rc = RexxStart(1,           /* 1 argument */
                        args,        /* argument array */
                        "TEST.CMD",  /* script path */
                        NULL,        /* not in-memory */
                        "CMD",       /* environment */
                        RXCOMMAND,   /* call type */
                        NULL,        /* no exits */
                        &retcode,    /* numeric return code */
                        &result);    /* string return value */

    printf("RexxStart rc=%ld, retcode=%d, result='%.*s'\n",
           rc, retcode,
           (int)result.strlength, result.strptr);

    /* Free if REXX allocated a new buffer */
    if (result.strptr != resbuf)
        DosFreeMem(result.strptr);

    return (int)rc;
}

Registering an external REXX function

#define INCL_REXXSAA
#define INCL_RXSHV
#include <rexxsaa.h>
#include <string.h>
#include <stdio.h>

/* External function: MYUPPER(string) — returns uppercase string */
ULONG APIENTRY MyUpperFunc(PUCHAR   name,
                           ULONG    argc,
                           PRXSTRING argv,
                           PSZ      queuename,
                           PRXSTRING result)
{
    if (argc != 1 || !RXVALIDSTRING(argv[0]))
        return 40; /* invalid call */

    /* Use the pre-allocated result buffer if big enough */
    if (result->strlength < argv[0].strlength)
        return 40; /* no room — caller should provide RXAUTOBUFLEN */

    ULONG i;
    for (i = 0; i < argv[0].strlength; i++)
        result->strptr[i] = toupper((unsigned char)argv[0].strptr[i]);
    result->strlength = argv[0].strlength;
    return 0;
}

int main(void)
{
    /* Register as a DLL function (current EXE) */
    RexxRegisterFunctionExe("MYUPPER", (PFN)MyUpperFunc);

    /* Run a REXX script that calls MYUPPER */
    RXSTRING result;
    SHORT    rc = 0;
    CHAR     buf[256];
    MAKERXSTRING(result, buf, sizeof(buf));

    RexxStart(0, NULL, "UPPER.CMD", NULL, "CMD", RXCOMMAND, NULL, &rc, &result);

    RexxDeregisterFunction("MYUPPER");
    return 0;
}

Intercepting REXX SAY output (RXSIO exit)

#define INCL_REXXSAA
#define INCL_RXSYSEXIT
#include <rexxsaa.h>
#include <stdio.h>

LONG APIENTRY MyExit(LONG exitcode, LONG subcode, PEXIT pblock)
{
    if (exitcode == RXSIO && subcode == RXSIOSAY) {
        RXSIOSAY_PARM *p = (RXSIOSAY_PARM *)pblock;
        /* redirect SAY output */
        fprintf(stderr, "[REXX] %.*s\n",
                (int)p->rxsio_string.strlength,
                p->rxsio_string.strptr);
        return RXEXIT_HANDLED;
    }
    return RXEXIT_NOT_HANDLED;
}

int main(void)
{
    RexxRegisterExitExe("MYIO", (PFN)MyExit, NULL);

    RXSYSEXIT exits[2];
    exits[0].sysexit_name = "MYIO";
    exits[0].sysexit_code = RXSIO;
    exits[1].sysexit_code = RXENDLST;

    SHORT    rc = 0;
    RXSTRING result;
    MAKERXSTRING(result, NULL, 0);

    RexxStart(0, NULL, "HELLO.CMD", NULL, "CMD",
              RXCOMMAND, exits, &rc, &result);

    RexxDeregisterExit("MYIO", NULL);
    return 0;
}

Accessing REXX variables from an external function

ULONG APIENTRY DumpVarsFunc(PUCHAR name, ULONG argc, PRXSTRING argv,
                             PSZ queue, PRXSTRING result)
{
    SHVBLOCK shv;
    shv.shvnext  = NULL;
    shv.shvcode  = RXSHV_NEXTV; /* enumerate all variables */
    shv.shvret   = 0;
    CHAR valbuf[4096];
    CHAR nambuf[256];
    MAKERXSTRING(shv.shvvalue, valbuf, sizeof(valbuf));
    MAKERXSTRING(shv.shvname,  nambuf, sizeof(nambuf));
    shv.shvnamelen  = sizeof(nambuf);
    shv.shvvaluelen = sizeof(valbuf);

    while (!(shv.shvret & RXSHV_LVAR)) {
        shv.shvnext = NULL;
        shv.shvcode = RXSHV_NEXTV;
        shv.shvret  = 0;
        RexxVariablePool(&shv);
        if (!(shv.shvret & (RXSHV_BADN | RXSHV_MEMFL))) {
            printf("%.*s = '%.*s'\n",
                   (int)shv.shvname.strlength,  shv.shvname.strptr,
                   (int)shv.shvvalue.strlength, shv.shvvalue.strptr);
        }
    }

    MAKERXSTRING(*result, "0", 1);
    return 0;
}

Version History

Version OS/2 release Date Notes
REXX 3.x (16-bit) OS/2 1.x 1988–1990 16-bit REXX interpreter. Basic RX* function names. No queue management API.
SAA REXX 4.0 (32-bit) OS/2 2.x 1992 32-bit SAA REXX; Rexx* mixed-case names introduced; Macro Space API added; Exit handler parameter blocks standardized.
Object REXX 6.0 OS/2 Warp 4 1996 IBM Object REXX replaces classic REXX; fully backward-compatible external API; queue management functions added (RexxCreateQueue, RexxDeleteQueue, RexxAddQueue, RexxPullQueue, RexxQueryQueue).
Final Toolkit 4.5 release OS/2 Warp 4.52 2001-04-09 File size 9,216 bytes. rexxsaa.h unchanged from Warp 4 release.

See Also