|
|
|
sdx_util
- String Descriptor (SDX) UtilitiesThe 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).
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.sdx_util.c
sdx_util.h
(See libgpl
for the complete source, including support routines and build files.)