1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
 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);
 }