sdx_util - String Descriptor (SDX) Utilities

The SDX_UTIL package provides functions for creating and manipulating dynamically sized and dynamically changing strings.

I was trying to clean up rexReplace(), which was going to great lengths to juggle the result string while making substitutions in an input string matched by a regular expression. To help me, I wrote this package; it was inspired by VAX/VMS descriptors which consisted of (i) 16 bits of flags including the data type of the object being described, (ii) the 16-bit length of the object, and (iii) the 32-bit address of the object.

I was aware of other libraries and, of course, C++, that support this functionality, but I don't like C++ and this simple package provided me with exactly what I wanted.

Building and using a string is easy:

    #include  "sdx_util.h"	-- String Descriptor utilities.
    StringDx  rdx ;
    sdxCreate ("I don't know why you say Goodbye",
               -1, SdxVolatile, &rdx) ;
    sdxAddC (rdx, ',') ;
    sdxAddC (rdx, ' ') ;
    sdxAddS (rdx, "I say Hello!", -1) ;
    printf ("Complete string: \"%s\"\n",
            sdxStringZ (rdx)) ;
    sdxDestroy (rdx) ;

The length argument, -1, in the calls to sdxCreate() and sdxAddS() specifies that the input string is NUL-terminated; these functions will call strlen(3) to determine the length. An actual length can be specified when adding a substring of a larger, SDX or non-SDX string.

If you're making repeated passes over something that requires a descriptor to be reset at the beginning of each pass, sdxErase() can be called to erase the contents of the descriptor without destroying the descriptor; if dynamically allocated, the existing, described string will be freed.

If you need a dynamically allocated string to survive the destruction of its descriptor, take ownership of the string:

    char  *result ;
    sdxOwn (rdx) ;
    result = sdxStringZ (rdx) ;
    sdxDestroy (rdx) ;
    free (result) ;		-- Don't forget to free the string.

If the caller owns the string, sdxDestroy() will not free the string. Note that, as a string grows, sdxAddC() and sdxAddS() may need to reallocate the buffer used to store the string. Consequently, a program should be sure to call sdxStringZ() right before destroying the descriptor in order to get the final address of the string.

NOTE: The SDX_UTIL functions can handle arbitrary-length strings with embedded NUL characters (zero bytes), but without a trailing NUL character. Instead of the C Library string functions, the SDX_UTIL functions use the memory functions: memcpy(3), memset(3), and memdup().

If the string length argument to an SDX_UTIL function is -1, the input string is assumed to be NUL-terminated and its length is determined using strlen(3).

The calling application is responsible for keeping track of and correctly handling NUL- and non-NUL-terminated strings. There are two special cases regarding the string returned by sdxStringZ() that the caller should be aware of. If the string passed to sdxCreate() was (i) SdxStatic or (ii) SdxDynamic (pre-allocated by the caller) and a length >= 0 was specified, the SDX_UTIL functions cannot tell if the input string is NUL-terminated; examining the character at length+1 is not permitted. Consequently, despite its name, sdxStringZ() may return a non-NUL-terminated string in these cases. The caller, again, is responsible for knowing what is what and not trying to print out a non-NUL-terminated string with an unadorned "%s" format.

There's no hope for static strings. In the latter case of a pre-allocated, dynamic string being passed to sdxCreate(), the first time text is added to the string via sdxAddC() or sdxAddS(), a trailing NUL terminator will be automatically added to the expanded string (even if the string already contains embedded NUL characters).

Public Procedures

sdxAddC() - adds a character to a described string.
sdxAddS() - adds text to a described string.
sdxCopy() - copy the contents from one described string to another.
sdxCreate() - creates a described string.
sdxDestroy() - destroys a described string.
sdxDuplicate() - duplicates a described string.
sdxErase() - erases the contents of a described string.
sdxGrow() - increases the size of a descriptor's string buffer.
sdxIncrement() - sets or gets the block size used to expand strings.
sdxLength() - returns the length of a described string.
sdxOwn() - takes ownership of a described string.
sdxSetLength() - sets the length of a described string.
sdxStringZ() - returns a described string as a NUL-terminated C string.

Source Files


Alex Measday  /  E-mail