herr_t
ss_string_splice(ss_string_t *str, /* String object to be modified by this operation. */
const char *value, /* Optional new data for part of the string value. If this argument is the
* null pointer and NBYTES is positive then the new data will be all NUL
* characters (this allows for an easy way to extend the length of a string). */
size_t start, /* Byte offset at which to place the new data in the string. */
size_t nbytes, /* Length of the new data in bytes. */
size_t nreplace /* Number of bytes replaced by the new data. If SS_NOSIZE is passed then all
* bytes from START to the end of the original value will be replaced by the
* new value. */
)
{
SS_ENTER(ss_string_splice, herr_t);
size_t newsize; /* New size of the string after modification */
char *tmpbuf=NULL; /* Temporary buffer for new value */
if (!str) SS_ERROR_FMT(USAGE, ("no ss_string_t supplied"));
if (start>str->nbytes) SS_ERROR_FMT(DOMAIN, ("new value starts after end of existing value"));
if (SS_NOSIZE==nreplace || start+nreplace>str->nbytes) nreplace = str->nbytes - start;
newsize = str->nbytes - nreplace + nbytes;
if (nbytes<=nreplace && 0==str->offset) {
/* String is not growing and str->p points to allocated memory and not into the string table. We can just splice
* in the new value in place. */
if (value) {
memcpy(str->p+start, value, nbytes); /*the inserted value*/
} else {
memset(str->p+start, 0, nbytes); /*the inserted NUL characters*/
}
memmove(str->p+start+nbytes, str->p+start+nreplace, str->nbytes-(start+nreplace)); /*move the rhs down*/
str->nbytes = newsize;
} else {
/* Value is growing or already assigned to a string table offset */
if (NULL==(tmpbuf=malloc(newsize))) SS_ERROR(RESOURCE);
memcpy(tmpbuf, str->p, start); /*the lhs stays put*/
if (value) {
memcpy(tmpbuf+start, value, nbytes); /*the inserted value*/
} else {
memset(tmpbuf+start, 0, nbytes); /*the inserted NUL characters*/
}
memcpy(tmpbuf+start+nbytes, str->p+start+nreplace, str->nbytes-(start+nreplace)); /*move the rhs down*/
if (nbytes!=nreplace || memcmp(str->p, tmpbuf, str->nbytes)) {
/* Value changed */
if (str->offset) {
str->offset = 0;
} else {
ss_string_reset(str);
/* SS_FREE(str->p); */
}
str->p = tmpbuf;
tmpbuf = NULL;
str->nbytes = newsize;
}
}
tmpbuf = SS_FREE(tmpbuf);
SS_CLEANUP:
SS_LEAVE(0);
}