Jump to content

RXSTRING.LIB

From EDM2

RXSTRING.LIB is a static utility library distributed with the IBM OS/2 Developer's Toolkit that provides C helper functions for working with the RXSTRING data type used by the OS/2 REXX interpreter. It is a companion to REXX.LIB (the REXX External Application Interface import library) and is intended for developers writing REXX external functions, subcommand handlers, and exit handlers in C.

Unlike REXX.LIB and other Toolkit import libraries, RXSTRING.LIB is a static library: its object code is linked directly into the calling application at build time. It has no corresponding DLL and adds no run-time dependency beyond REXX.DLL (which external functions already require). All functions are 32-bit only; for 16-bit RXSTRING support, the OS/2 1.2 or 1.3 Toolkit version of RXSTRING.LIB must be used.

File size in the OS/2 Warp 4.52 Toolkit 4.5: 6,191 bytes. Copyright: IBM Corporation 1992, 1996. Distributed with the Toolkit in os2tk45\lib\rxstring.lib; documentation in os2tk45\book\rxstring.doc.

Background

The REXX External Application Interface passes all string data between C code and the REXX interpreter as RXSTRING structures:

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

Because RXSTRING strings are length-delimited rather than null-terminated, the standard C library string functions (strcpy, strlen, strcmp, etc.) cannot be applied directly. RXSTRING.LIB provides analogues for these functions that operate on the RXSTRING structure, plus conversion utilities for moving data between C strings/PUCHAR buffers and RXSTRINGs.

Include Files

RXSTRING.LIB has no distributed header in the Toolkit 4.5. Function prototypes must be declared by the application. The RXSTRING type itself is declared in rexxsaa.h:

#define INCL_REXXSAA
#include <rexxsaa.h>

Suggested forward declarations for the functions most commonly used:

/* Numeric conversion */
INT    rxtoi(RXSTRING rx);
LONG   rxtol(RXSTRING rx);
ULONG  rxtoul(RXSTRING rx);

/* Memory management */
RXSTRING rxalloc(ULONG ulSize);
VOID     rxfree(RXSTRING rx);

/* Return value helper */
RXSTRING rxreturn_value(PRXSTRING presult, PUCHAR pdata, ULONG ulLen);

/* Length helpers */
ULONG    rxstrlen(RXSTRING rx);
RXSTRING rxset_null(PRXSTRING prx);
RXSTRING rxset_zerolen(PRXSTRING prx);

/* Copy / cat */
RXSTRING rxstrcpy(PRXSTRING pdest, PRXSTRING psrc);
RXSTRING rxstrcat(PRXSTRING pdest, PRXSTRING psrc);
RXSTRING strcpy2rx(PRXSTRING pdest, PSZ pszSrc);
RXSTRING strcat2rx(PRXSTRING pdest, PSZ pszSrc);
RXSTRING strdup2rx(PUCHAR pSrc, ULONG ulLen);

/* Comparison */
LONG   rxstrcmp(PRXSTRING p1, PRXSTRING p2);
LONG   rxstricmp(PRXSTRING p1, PRXSTRING p2);
PUCHAR rxstrchr(PRXSTRING prx, UCHAR ch);
PUCHAR rxstrrchr(PRXSTRING prx, UCHAR ch);

/* I/O */
VOID rxprint(RXSTRING rx);

API Reference

Group 1: Numeric Conversion

These functions convert an RXSTRING containing a numeric string into a C integer value, analogous to atoi(), atol(), and strtoul().

INT rxtoi(RXSTRING rx)
Converts the RXSTRING rx to an INT. Equivalent to atoi() on the string data. Leading whitespace is skipped; conversion stops at the first non-numeric character.
LONG rxtol(RXSTRING rx)
Converts the RXSTRING rx to a LONG. Equivalent to atol().
ULONG rxtoul(RXSTRING rx)
Converts the RXSTRING rx to a ULONG. Equivalent to strtoul(). Useful for parsing numeric REXX arguments passed to an external function.

Group 2: File I/O

These functions read and write RXSTRING data to OS/2 file handles, and print RXSTRING contents to stdout. They operate on the raw bytes in the RXSTRING (not null-terminated output).

LONG rxwrite(HFILE hf, RXSTRING rx)
Writes the string data in rx to file handle hf using DosWrite. Returns the number of bytes written, or a negative error code.
LONG rxread(HFILE hf, PRXSTRING prx)
Reads data from file handle hf into the RXSTRING pointed to by prx using DosRead. The RXSTRING must already have allocated storage (strptr pointing to a buffer of strlength bytes). Returns the number of bytes read.
VOID rxprint(RXSTRING rx)
Writes the string data contained in rx to stdout using fputc. No newline is appended. Useful for quick debugging output from REXX external functions.

Group 3: Copy and Conversion

These functions copy, duplicate, and concatenate RXSTRING data. The "2rx" suffix functions convert from C strings or raw buffers to RXSTRING; the rx* functions operate on RXSTRING-to-RXSTRING.

Important: Except for the "dup" variants, all functions require that the destination RXSTRING already contains sufficient allocated storage. Concatenation functions append starting at the current strlength position — the destination buffer must hold the existing data plus the new data.

RXSTRING rxstrdup(RXSTRING rx)
Allocates a new RXSTRING and copies the data from rx into it. The caller is responsible for freeing the result with rxfree. Returns a null RXSTRING on allocation failure.
RXSTRING rxmemcpy(PRXSTRING pdest, PRXSTRING psrc, ULONG ulLen)
Copies exactly ulLen bytes from psrc into pdest. The destination must already have at least ulLen bytes allocated. Sets pdest->strlength = ulLen.
RXSTRING rxstrcpy(PRXSTRING pdest, PRXSTRING psrc)
Copies the full contents of psrc into pdest. The destination must have storage for psrc->strlength bytes.
RXSTRING rxstrncpy(PRXSTRING pdest, PRXSTRING psrc, ULONG ulLen)
Copies at most ulLen bytes from psrc into pdest.
RXSTRING rxstrcat(PRXSTRING pdest, PRXSTRING psrc)
Appends the contents of psrc to pdest, starting at pdest->strlength. Updates pdest->strlength accordingly. The destination buffer must have sufficient space.
RXSTRING rxstrncat(PRXSTRING pdest, PRXSTRING psrc, ULONG ulLen)
Appends at most ulLen bytes from psrc to pdest.
RXSTRING strdup2rx(PUCHAR pSrc, ULONG ulLen)
Allocates a new RXSTRING and copies ulLen bytes from the raw buffer pSrc into it. Equivalent to combining DosAllocMem + memcpy. The caller must free the result with rxfree.
RXSTRING memcpy2rx(PRXSTRING pdest, PUCHAR pSrc, ULONG ulLen)
Copies ulLen bytes from the raw buffer pSrc into the pre-allocated RXSTRING pdest.
RXSTRING strcpy2rx(PRXSTRING pdest, PSZ pszSrc)
Copies a null-terminated C string pszSrc into the pre-allocated RXSTRING pdest. Sets strlength to the C string length (not counting the null terminator).
RXSTRING strcat2rx(PRXSTRING pdest, PSZ pszSrc)
Appends the null-terminated C string pszSrc to the pre-allocated RXSTRING pdest.
RXSTRING strncat2rx(PRXSTRING pdest, PSZ pszSrc, ULONG ulLen)
Appends at most ulLen bytes from the C string pszSrc to pdest.

Group 4: Comparison and Character Search

These functions are RXSTRING analogues of the standard C library comparison and character-search functions.

LONG rxstrcmp(PRXSTRING p1, PRXSTRING p2)
Case-sensitive comparison. Returns negative if p1 < p2, 0 if equal, positive if p1 > p2. Analogous to strcmp().
LONG rxstricmp(PRXSTRING p1, PRXSTRING p2)
Case-insensitive comparison. Analogous to stricmp() / strcasecmp().
LONG rxmemcmp(PRXSTRING p1, PRXSTRING p2, ULONG ulLen)
Compares exactly ulLen bytes from each RXSTRING, case-sensitively. Analogous to memcmp().
LONG rxmemicmp(PRXSTRING p1, PRXSTRING p2, ULONG ulLen)
Compares exactly ulLen bytes case-insensitively. Analogous to memicmp().
PUCHAR rxstrchr(PRXSTRING prx, UCHAR ch)
Searches for the first occurrence of byte ch in the RXSTRING. Returns a pointer to the matching byte within the string buffer, or NULL if not found. Analogous to strchr().
PUCHAR rxstrrchr(PRXSTRING prx, UCHAR ch)
Searches for the last occurrence of byte ch in the RXSTRING. Returns a pointer to the last matching byte, or NULL. Analogous to strrchr().

Group 5: Miscellaneous

RXSTRING rxalloc(ULONG ulSize)
Allocates a new RXSTRING with a data buffer of ulSize bytes, using DosAllocMem. Sets strlength = ulSize and strptr to the allocated memory. Returns a null RXSTRING (both fields zero) on failure. Free the result with rxfree.
VOID rxfree(RXSTRING rx)
Frees the storage associated with an RXSTRING previously allocated by rxalloc, rxstrdup, or strdup2rx, using DosFreeMem. Passing a null RXSTRING is safe (no-op).
VOID rxstrnset(RXSTRING rx, UCHAR ch, ULONG ulLen)
Fills the first ulLen bytes of rx's buffer with the byte value ch. Analogous to memset(). Does not modify strlength.
ULONG rxstrlen(RXSTRING rx)
Returns the strlength field of the RXSTRING. This is a convenience accessor that does not compute the length from the data (unlike strlen() on C strings). Returns 0 for a null or zero-length RXSTRING.
RXSTRING rxset_length(PRXSTRING prx, ULONG ulLen)
Sets the strlength field of the RXSTRING to ulLen without modifying the associated memory. Useful for trimming or extending the reported length of an RXSTRING after manual buffer manipulation.
RXSTRING rxset_null(PRXSTRING prx)
Sets the RXSTRING to a null string: strptr = NULL, strlength = 0. The equivalent of MAKERXSTRING(*prx, NULL, 0).
RXSTRING rxset_zerolen(PRXSTRING prx)
Sets the RXSTRING to a zero-length string: strlength = 0 without clearing strptr. The RXSTRING is valid (non-null) but contains an empty string.
RXSTRING rxreturn_value(PRXSTRING presult, PUCHAR pdata, ULONG ulLen)
Helper for filling in the return value RXSTRING in a REXX external function or subcommand handler callback. If the pre-allocated buffer in presult is large enough for ulLen bytes, the data is copied there; otherwise a new buffer is allocated (the original is freed). This removes the need for callers to manually implement the "use pre-allocated buffer or allocate a new one" pattern required by the REXX External API. Returns the updated RXSTRING.
PUCHAR _make_hptr(RXSTRING rx)
Returns a flat 32-bit pointer to the string data buffer of rx, converting from the selector:offset representation used in 16-bit OS/2 segments if necessary (via _DosSelToFlat). In 32-bit flat-model code this is equivalent to returning rx.strptr directly; the function exists for source compatibility with 16-bit code paths.

Additional Symbols (Undocumented)

The following symbols are present in the library object code but are not documented in the official rxstring.doc:

Symbol Notes
RXNUMBER / RXNUMBERN Format a numeric value into an RXSTRING buffer
RXSTRCMP Uppercase alias for rxstrcmp
RXSTRCPY2 Variant of rxstrcpy
rxstrcmpn / rxstricmpn Bounded (n-byte) comparison variants
rxmemcmpn / rxmemicmpn Bounded memory comparison variants
rxstrchr0 Variant of rxstrchr, possibly including a null-byte search
rxstrrchrl Variant of rxstrrchr
rxstrcatX / rxstrncatx Extended concatenation variants
rxallocL Large-allocation variant of rxalloc
rxprintt Variant of rxprint
rxreturn_valuet Variant of rxreturn_value
strdup2rx8 Variant of strdup2rx

Usage

Build Instructions

RXSTRING.LIB is a static library; link it directly alongside the standard OS/2 import libraries. No separate DLL is needed at run time.

IBM VisualAge C++ / ILINK

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

OpenWatcom

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

EMX/GCC

gcc -Zomf -c myfunc.c
gcc -Zomf -o myfunc.exe myfunc.o -los2386 -lrexx -lrxstring

Writing an External REXX Function

The following example shows a complete external function STRREVERSE using RXSTRING.LIB helpers:

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

/* Forward declarations for RXSTRING.LIB functions (no header supplied) */
RXSTRING rxalloc(ULONG ulSize);
VOID     rxfree(RXSTRING rx);
RXSTRING rxreturn_value(PRXSTRING presult, PUCHAR pdata, ULONG ulLen);
ULONG    rxstrlen(RXSTRING rx);

/* STRREVERSE(string) — returns the string with its bytes reversed */
ULONG APIENTRY StrReverseFunc(PUCHAR   funcname,
                              ULONG    argc,
                              PRXSTRING argv,
                              PSZ      queuename,
                              PRXSTRING result)
{
    ULONG   len, i;
    RXSTRING tmp;
    PUCHAR   p;

    if (argc != 1 || !RXVALIDSTRING(argv[0]))
        return 40; /* invalid call */

    len = rxstrlen(argv[0]);
    tmp = rxalloc(len);
    if (!RXVALIDSTRING(tmp))
        return 40; /* allocation failure */

    p = tmp.strptr;
    for (i = 0; i < len; i++)
        p[i] = argv[0].strptr[len - 1 - i];

    rxreturn_value(result, tmp.strptr, len);
    rxfree(tmp);
    return 0;
}

Parsing a Numeric Argument

#define INCL_REXXSAA
#include <rexxsaa.h>

ULONG  rxtoul(RXSTRING rx);
RXSTRING rxalloc(ULONG);
RXSTRING rxreturn_value(PRXSTRING, PUCHAR, ULONG);

/* FACTSTR(n) — returns n! as a string (demo; overflows past 12!) */
ULONG APIENTRY FactorialFunc(PUCHAR name, ULONG argc, PRXSTRING argv,
                              PSZ queue, PRXSTRING result)
{
    ULONG  n, f, i;
    CHAR   buf[32];
    ULONG  len;

    if (argc != 1 || !RXVALIDSTRING(argv[0]))
        return 40;

    n = rxtoul(argv[0]);   /* convert RXSTRING "12" → ULONG 12 */
    f = 1;
    for (i = 2; i <= n; i++) f *= i;

    len = sprintf(buf, "%lu", f);
    rxreturn_value(result, (PUCHAR)buf, len);
    return 0;
}

Converting a C String Result to RXSTRING

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

RXSTRING strdup2rx(PUCHAR pSrc, ULONG ulLen);
RXSTRING rxreturn_value(PRXSTRING presult, PUCHAR pdata, ULONG ulLen);
VOID     rxfree(RXSTRING rx);

/* ENVVAR(name) — returns the value of an environment variable */
ULONG APIENTRY EnvVarFunc(PUCHAR name, ULONG argc, PRXSTRING argv,
                           PSZ queue, PRXSTRING result)
{
    PSZ   pszVal;
    ULONG len;

    if (argc != 1 || !RXVALIDSTRING(argv[0]))
        return 40;

    /* Null-terminate the argument for DosScanEnv */
    CHAR szName[256];
    memcpy(szName, argv[0].strptr, argv[0].strlength);
    szName[argv[0].strlength] = '\0';

    if (DosScanEnv(szName, &pszVal) != 0) {
        /* Return empty string if not found */
        result->strlength = 0;
        return 0;
    }

    len = strlen(pszVal);
    rxreturn_value(result, (PUCHAR)pszVal, len);
    return 0;
}

Notes

  • Not null-terminated: RXSTRING data is never null-terminated. Do not pass rx.strptr directly to standard C library functions that expect a PSZ / char *. Use the strcpy2rx / strdup2rx family to convert, or null-terminate manually before calling C string functions.
  • rxreturn_value ownership: When rxreturn_value allocates a new buffer (because the pre-allocated one was too small), the data pointer is replaced via DosAllocMem; the REXX interpreter then owns and will free that buffer. Do not double-free it.
  • rxalloc / rxfree use DosAllocMem: This means allocated memory is page-aligned. Do not mix with malloc/free.
  • 32-bit only: All functions are compiled for the 32-bit flat address model. The 16-bit Toolkit variant (OS/2 1.x Toolkit) must be used for 16-bit applications.
  • RXFILEIO module: The I/O functions (rxwrite, rxread, rxprint) are compiled as a separate OMF module named RXFILEIO within the library. Linking will only pull in this module if one of the I/O functions is referenced.

Version History

Toolkit version OS/2 release Notes
OS/2 1.2 / 1.3 Toolkit OS/2 1.x 16-bit RXSTRING.LIB; original release
OS/2 2.0 Toolkit OS/2 2.0 (1992) 32-bit rewrite; "Cruiser" development codename visible in OMF segment names; functions documented in rxstring.doc
Toolkit 4.5 OS/2 Warp 4.52 Final release; 6,191 bytes; copyright 1992, 1996; rxstring.doc in os2tk45\book\

See Also