"Fossies" - the Fresh Open Source Software Archive

Member "redis-5.0.6/src/sds.c" (25 Sep 2019, 40753 Bytes) of package /linux/misc/redis-5.0.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "sds.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 5.0.3_vs_5.0.4.

    1 /* SDSLib 2.0 -- A C dynamic strings library
    2  *
    3  * Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
    4  * Copyright (c) 2015, Oran Agra
    5  * Copyright (c) 2015, Redis Labs, Inc
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions are met:
   10  *
   11  *   * Redistributions of source code must retain the above copyright notice,
   12  *     this list of conditions and the following disclaimer.
   13  *   * Redistributions in binary form must reproduce the above copyright
   14  *     notice, this list of conditions and the following disclaimer in the
   15  *     documentation and/or other materials provided with the distribution.
   16  *   * Neither the name of Redis nor the names of its contributors may be used
   17  *     to endorse or promote products derived from this software without
   18  *     specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include <stdio.h>
   34 #include <stdlib.h>
   35 #include <string.h>
   36 #include <ctype.h>
   37 #include <assert.h>
   38 #include <limits.h>
   39 #include "sds.h"
   40 #include "sdsalloc.h"
   41 
   42 const char *SDS_NOINIT = "SDS_NOINIT";
   43 
   44 static inline int sdsHdrSize(char type) {
   45     switch(type&SDS_TYPE_MASK) {
   46         case SDS_TYPE_5:
   47             return sizeof(struct sdshdr5);
   48         case SDS_TYPE_8:
   49             return sizeof(struct sdshdr8);
   50         case SDS_TYPE_16:
   51             return sizeof(struct sdshdr16);
   52         case SDS_TYPE_32:
   53             return sizeof(struct sdshdr32);
   54         case SDS_TYPE_64:
   55             return sizeof(struct sdshdr64);
   56     }
   57     return 0;
   58 }
   59 
   60 static inline char sdsReqType(size_t string_size) {
   61     if (string_size < 1<<5)
   62         return SDS_TYPE_5;
   63     if (string_size < 1<<8)
   64         return SDS_TYPE_8;
   65     if (string_size < 1<<16)
   66         return SDS_TYPE_16;
   67 #if (LONG_MAX == LLONG_MAX)
   68     if (string_size < 1ll<<32)
   69         return SDS_TYPE_32;
   70     return SDS_TYPE_64;
   71 #else
   72     return SDS_TYPE_32;
   73 #endif
   74 }
   75 
   76 /* Create a new sds string with the content specified by the 'init' pointer
   77  * and 'initlen'.
   78  * If NULL is used for 'init' the string is initialized with zero bytes.
   79  * If SDS_NOINIT is used, the buffer is left uninitialized;
   80  *
   81  * The string is always null-termined (all the sds strings are, always) so
   82  * even if you create an sds string with:
   83  *
   84  * mystring = sdsnewlen("abc",3);
   85  *
   86  * You can print the string with printf() as there is an implicit \0 at the
   87  * end of the string. However the string is binary safe and can contain
   88  * \0 characters in the middle, as the length is stored in the sds header. */
   89 sds sdsnewlen(const void *init, size_t initlen) {
   90     void *sh;
   91     sds s;
   92     char type = sdsReqType(initlen);
   93     /* Empty strings are usually created in order to append. Use type 8
   94      * since type 5 is not good at this. */
   95     if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8;
   96     int hdrlen = sdsHdrSize(type);
   97     unsigned char *fp; /* flags pointer. */
   98 
   99     sh = s_malloc(hdrlen+initlen+1);
  100     if (init==SDS_NOINIT)
  101         init = NULL;
  102     else if (!init)
  103         memset(sh, 0, hdrlen+initlen+1);
  104     if (sh == NULL) return NULL;
  105     s = (char*)sh+hdrlen;
  106     fp = ((unsigned char*)s)-1;
  107     switch(type) {
  108         case SDS_TYPE_5: {
  109             *fp = type | (initlen << SDS_TYPE_BITS);
  110             break;
  111         }
  112         case SDS_TYPE_8: {
  113             SDS_HDR_VAR(8,s);
  114             sh->len = initlen;
  115             sh->alloc = initlen;
  116             *fp = type;
  117             break;
  118         }
  119         case SDS_TYPE_16: {
  120             SDS_HDR_VAR(16,s);
  121             sh->len = initlen;
  122             sh->alloc = initlen;
  123             *fp = type;
  124             break;
  125         }
  126         case SDS_TYPE_32: {
  127             SDS_HDR_VAR(32,s);
  128             sh->len = initlen;
  129             sh->alloc = initlen;
  130             *fp = type;
  131             break;
  132         }
  133         case SDS_TYPE_64: {
  134             SDS_HDR_VAR(64,s);
  135             sh->len = initlen;
  136             sh->alloc = initlen;
  137             *fp = type;
  138             break;
  139         }
  140     }
  141     if (initlen && init)
  142         memcpy(s, init, initlen);
  143     s[initlen] = '\0';
  144     return s;
  145 }
  146 
  147 /* Create an empty (zero length) sds string. Even in this case the string
  148  * always has an implicit null term. */
  149 sds sdsempty(void) {
  150     return sdsnewlen("",0);
  151 }
  152 
  153 /* Create a new sds string starting from a null terminated C string. */
  154 sds sdsnew(const char *init) {
  155     size_t initlen = (init == NULL) ? 0 : strlen(init);
  156     return sdsnewlen(init, initlen);
  157 }
  158 
  159 /* Duplicate an sds string. */
  160 sds sdsdup(const sds s) {
  161     return sdsnewlen(s, sdslen(s));
  162 }
  163 
  164 /* Free an sds string. No operation is performed if 's' is NULL. */
  165 void sdsfree(sds s) {
  166     if (s == NULL) return;
  167     s_free((char*)s-sdsHdrSize(s[-1]));
  168 }
  169 
  170 /* Set the sds string length to the length as obtained with strlen(), so
  171  * considering as content only up to the first null term character.
  172  *
  173  * This function is useful when the sds string is hacked manually in some
  174  * way, like in the following example:
  175  *
  176  * s = sdsnew("foobar");
  177  * s[2] = '\0';
  178  * sdsupdatelen(s);
  179  * printf("%d\n", sdslen(s));
  180  *
  181  * The output will be "2", but if we comment out the call to sdsupdatelen()
  182  * the output will be "6" as the string was modified but the logical length
  183  * remains 6 bytes. */
  184 void sdsupdatelen(sds s) {
  185     size_t reallen = strlen(s);
  186     sdssetlen(s, reallen);
  187 }
  188 
  189 /* Modify an sds string in-place to make it empty (zero length).
  190  * However all the existing buffer is not discarded but set as free space
  191  * so that next append operations will not require allocations up to the
  192  * number of bytes previously available. */
  193 void sdsclear(sds s) {
  194     sdssetlen(s, 0);
  195     s[0] = '\0';
  196 }
  197 
  198 /* Enlarge the free space at the end of the sds string so that the caller
  199  * is sure that after calling this function can overwrite up to addlen
  200  * bytes after the end of the string, plus one more byte for nul term.
  201  *
  202  * Note: this does not change the *length* of the sds string as returned
  203  * by sdslen(), but only the free buffer space we have. */
  204 sds sdsMakeRoomFor(sds s, size_t addlen) {
  205     void *sh, *newsh;
  206     size_t avail = sdsavail(s);
  207     size_t len, newlen;
  208     char type, oldtype = s[-1] & SDS_TYPE_MASK;
  209     int hdrlen;
  210 
  211     /* Return ASAP if there is enough space left. */
  212     if (avail >= addlen) return s;
  213 
  214     len = sdslen(s);
  215     sh = (char*)s-sdsHdrSize(oldtype);
  216     newlen = (len+addlen);
  217     if (newlen < SDS_MAX_PREALLOC)
  218         newlen *= 2;
  219     else
  220         newlen += SDS_MAX_PREALLOC;
  221 
  222     type = sdsReqType(newlen);
  223 
  224     /* Don't use type 5: the user is appending to the string and type 5 is
  225      * not able to remember empty space, so sdsMakeRoomFor() must be called
  226      * at every appending operation. */
  227     if (type == SDS_TYPE_5) type = SDS_TYPE_8;
  228 
  229     hdrlen = sdsHdrSize(type);
  230     if (oldtype==type) {
  231         newsh = s_realloc(sh, hdrlen+newlen+1);
  232         if (newsh == NULL) return NULL;
  233         s = (char*)newsh+hdrlen;
  234     } else {
  235         /* Since the header size changes, need to move the string forward,
  236          * and can't use realloc */
  237         newsh = s_malloc(hdrlen+newlen+1);
  238         if (newsh == NULL) return NULL;
  239         memcpy((char*)newsh+hdrlen, s, len+1);
  240         s_free(sh);
  241         s = (char*)newsh+hdrlen;
  242         s[-1] = type;
  243         sdssetlen(s, len);
  244     }
  245     sdssetalloc(s, newlen);
  246     return s;
  247 }
  248 
  249 /* Reallocate the sds string so that it has no free space at the end. The
  250  * contained string remains not altered, but next concatenation operations
  251  * will require a reallocation.
  252  *
  253  * After the call, the passed sds string is no longer valid and all the
  254  * references must be substituted with the new pointer returned by the call. */
  255 sds sdsRemoveFreeSpace(sds s) {
  256     void *sh, *newsh;
  257     char type, oldtype = s[-1] & SDS_TYPE_MASK;
  258     int hdrlen, oldhdrlen = sdsHdrSize(oldtype);
  259     size_t len = sdslen(s);
  260     size_t avail = sdsavail(s);
  261     sh = (char*)s-oldhdrlen;
  262 
  263     /* Return ASAP if there is no space left. */
  264     if (avail == 0) return s;
  265 
  266     /* Check what would be the minimum SDS header that is just good enough to
  267      * fit this string. */
  268     type = sdsReqType(len);
  269     hdrlen = sdsHdrSize(type);
  270 
  271     /* If the type is the same, or at least a large enough type is still
  272      * required, we just realloc(), letting the allocator to do the copy
  273      * only if really needed. Otherwise if the change is huge, we manually
  274      * reallocate the string to use the different header type. */
  275     if (oldtype==type || type > SDS_TYPE_8) {
  276         newsh = s_realloc(sh, oldhdrlen+len+1);
  277         if (newsh == NULL) return NULL;
  278         s = (char*)newsh+oldhdrlen;
  279     } else {
  280         newsh = s_malloc(hdrlen+len+1);
  281         if (newsh == NULL) return NULL;
  282         memcpy((char*)newsh+hdrlen, s, len+1);
  283         s_free(sh);
  284         s = (char*)newsh+hdrlen;
  285         s[-1] = type;
  286         sdssetlen(s, len);
  287     }
  288     sdssetalloc(s, len);
  289     return s;
  290 }
  291 
  292 /* Return the total size of the allocation of the specified sds string,
  293  * including:
  294  * 1) The sds header before the pointer.
  295  * 2) The string.
  296  * 3) The free buffer at the end if any.
  297  * 4) The implicit null term.
  298  */
  299 size_t sdsAllocSize(sds s) {
  300     size_t alloc = sdsalloc(s);
  301     return sdsHdrSize(s[-1])+alloc+1;
  302 }
  303 
  304 /* Return the pointer of the actual SDS allocation (normally SDS strings
  305  * are referenced by the start of the string buffer). */
  306 void *sdsAllocPtr(sds s) {
  307     return (void*) (s-sdsHdrSize(s[-1]));
  308 }
  309 
  310 /* Increment the sds length and decrements the left free space at the
  311  * end of the string according to 'incr'. Also set the null term
  312  * in the new end of the string.
  313  *
  314  * This function is used in order to fix the string length after the
  315  * user calls sdsMakeRoomFor(), writes something after the end of
  316  * the current string, and finally needs to set the new length.
  317  *
  318  * Note: it is possible to use a negative increment in order to
  319  * right-trim the string.
  320  *
  321  * Usage example:
  322  *
  323  * Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the
  324  * following schema, to cat bytes coming from the kernel to the end of an
  325  * sds string without copying into an intermediate buffer:
  326  *
  327  * oldlen = sdslen(s);
  328  * s = sdsMakeRoomFor(s, BUFFER_SIZE);
  329  * nread = read(fd, s+oldlen, BUFFER_SIZE);
  330  * ... check for nread <= 0 and handle it ...
  331  * sdsIncrLen(s, nread);
  332  */
  333 void sdsIncrLen(sds s, ssize_t incr) {
  334     unsigned char flags = s[-1];
  335     size_t len;
  336     switch(flags&SDS_TYPE_MASK) {
  337         case SDS_TYPE_5: {
  338             unsigned char *fp = ((unsigned char*)s)-1;
  339             unsigned char oldlen = SDS_TYPE_5_LEN(flags);
  340             assert((incr > 0 && oldlen+incr < 32) || (incr < 0 && oldlen >= (unsigned int)(-incr)));
  341             *fp = SDS_TYPE_5 | ((oldlen+incr) << SDS_TYPE_BITS);
  342             len = oldlen+incr;
  343             break;
  344         }
  345         case SDS_TYPE_8: {
  346             SDS_HDR_VAR(8,s);
  347             assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
  348             len = (sh->len += incr);
  349             break;
  350         }
  351         case SDS_TYPE_16: {
  352             SDS_HDR_VAR(16,s);
  353             assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
  354             len = (sh->len += incr);
  355             break;
  356         }
  357         case SDS_TYPE_32: {
  358             SDS_HDR_VAR(32,s);
  359             assert((incr >= 0 && sh->alloc-sh->len >= (unsigned int)incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
  360             len = (sh->len += incr);
  361             break;
  362         }
  363         case SDS_TYPE_64: {
  364             SDS_HDR_VAR(64,s);
  365             assert((incr >= 0 && sh->alloc-sh->len >= (uint64_t)incr) || (incr < 0 && sh->len >= (uint64_t)(-incr)));
  366             len = (sh->len += incr);
  367             break;
  368         }
  369         default: len = 0; /* Just to avoid compilation warnings. */
  370     }
  371     s[len] = '\0';
  372 }
  373 
  374 /* Grow the sds to have the specified length. Bytes that were not part of
  375  * the original length of the sds will be set to zero.
  376  *
  377  * if the specified length is smaller than the current length, no operation
  378  * is performed. */
  379 sds sdsgrowzero(sds s, size_t len) {
  380     size_t curlen = sdslen(s);
  381 
  382     if (len <= curlen) return s;
  383     s = sdsMakeRoomFor(s,len-curlen);
  384     if (s == NULL) return NULL;
  385 
  386     /* Make sure added region doesn't contain garbage */
  387     memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */
  388     sdssetlen(s, len);
  389     return s;
  390 }
  391 
  392 /* Append the specified binary-safe string pointed by 't' of 'len' bytes to the
  393  * end of the specified sds string 's'.
  394  *
  395  * After the call, the passed sds string is no longer valid and all the
  396  * references must be substituted with the new pointer returned by the call. */
  397 sds sdscatlen(sds s, const void *t, size_t len) {
  398     size_t curlen = sdslen(s);
  399 
  400     s = sdsMakeRoomFor(s,len);
  401     if (s == NULL) return NULL;
  402     memcpy(s+curlen, t, len);
  403     sdssetlen(s, curlen+len);
  404     s[curlen+len] = '\0';
  405     return s;
  406 }
  407 
  408 /* Append the specified null termianted C string to the sds string 's'.
  409  *
  410  * After the call, the passed sds string is no longer valid and all the
  411  * references must be substituted with the new pointer returned by the call. */
  412 sds sdscat(sds s, const char *t) {
  413     return sdscatlen(s, t, strlen(t));
  414 }
  415 
  416 /* Append the specified sds 't' to the existing sds 's'.
  417  *
  418  * After the call, the modified sds string is no longer valid and all the
  419  * references must be substituted with the new pointer returned by the call. */
  420 sds sdscatsds(sds s, const sds t) {
  421     return sdscatlen(s, t, sdslen(t));
  422 }
  423 
  424 /* Destructively modify the sds string 's' to hold the specified binary
  425  * safe string pointed by 't' of length 'len' bytes. */
  426 sds sdscpylen(sds s, const char *t, size_t len) {
  427     if (sdsalloc(s) < len) {
  428         s = sdsMakeRoomFor(s,len-sdslen(s));
  429         if (s == NULL) return NULL;
  430     }
  431     memcpy(s, t, len);
  432     s[len] = '\0';
  433     sdssetlen(s, len);
  434     return s;
  435 }
  436 
  437 /* Like sdscpylen() but 't' must be a null-termined string so that the length
  438  * of the string is obtained with strlen(). */
  439 sds sdscpy(sds s, const char *t) {
  440     return sdscpylen(s, t, strlen(t));
  441 }
  442 
  443 /* Helper for sdscatlonglong() doing the actual number -> string
  444  * conversion. 's' must point to a string with room for at least
  445  * SDS_LLSTR_SIZE bytes.
  446  *
  447  * The function returns the length of the null-terminated string
  448  * representation stored at 's'. */
  449 #define SDS_LLSTR_SIZE 21
  450 int sdsll2str(char *s, long long value) {
  451     char *p, aux;
  452     unsigned long long v;
  453     size_t l;
  454 
  455     /* Generate the string representation, this method produces
  456      * an reversed string. */
  457     v = (value < 0) ? -value : value;
  458     p = s;
  459     do {
  460         *p++ = '0'+(v%10);
  461         v /= 10;
  462     } while(v);
  463     if (value < 0) *p++ = '-';
  464 
  465     /* Compute length and add null term. */
  466     l = p-s;
  467     *p = '\0';
  468 
  469     /* Reverse the string. */
  470     p--;
  471     while(s < p) {
  472         aux = *s;
  473         *s = *p;
  474         *p = aux;
  475         s++;
  476         p--;
  477     }
  478     return l;
  479 }
  480 
  481 /* Identical sdsll2str(), but for unsigned long long type. */
  482 int sdsull2str(char *s, unsigned long long v) {
  483     char *p, aux;
  484     size_t l;
  485 
  486     /* Generate the string representation, this method produces
  487      * an reversed string. */
  488     p = s;
  489     do {
  490         *p++ = '0'+(v%10);
  491         v /= 10;
  492     } while(v);
  493 
  494     /* Compute length and add null term. */
  495     l = p-s;
  496     *p = '\0';
  497 
  498     /* Reverse the string. */
  499     p--;
  500     while(s < p) {
  501         aux = *s;
  502         *s = *p;
  503         *p = aux;
  504         s++;
  505         p--;
  506     }
  507     return l;
  508 }
  509 
  510 /* Create an sds string from a long long value. It is much faster than:
  511  *
  512  * sdscatprintf(sdsempty(),"%lld\n", value);
  513  */
  514 sds sdsfromlonglong(long long value) {
  515     char buf[SDS_LLSTR_SIZE];
  516     int len = sdsll2str(buf,value);
  517 
  518     return sdsnewlen(buf,len);
  519 }
  520 
  521 /* Like sdscatprintf() but gets va_list instead of being variadic. */
  522 sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
  523     va_list cpy;
  524     char staticbuf[1024], *buf = staticbuf, *t;
  525     size_t buflen = strlen(fmt)*2;
  526 
  527     /* We try to start using a static buffer for speed.
  528      * If not possible we revert to heap allocation. */
  529     if (buflen > sizeof(staticbuf)) {
  530         buf = s_malloc(buflen);
  531         if (buf == NULL) return NULL;
  532     } else {
  533         buflen = sizeof(staticbuf);
  534     }
  535 
  536     /* Try with buffers two times bigger every time we fail to
  537      * fit the string in the current buffer size. */
  538     while(1) {
  539         buf[buflen-2] = '\0';
  540         va_copy(cpy,ap);
  541         vsnprintf(buf, buflen, fmt, cpy);
  542         va_end(cpy);
  543         if (buf[buflen-2] != '\0') {
  544             if (buf != staticbuf) s_free(buf);
  545             buflen *= 2;
  546             buf = s_malloc(buflen);
  547             if (buf == NULL) return NULL;
  548             continue;
  549         }
  550         break;
  551     }
  552 
  553     /* Finally concat the obtained string to the SDS string and return it. */
  554     t = sdscat(s, buf);
  555     if (buf != staticbuf) s_free(buf);
  556     return t;
  557 }
  558 
  559 /* Append to the sds string 's' a string obtained using printf-alike format
  560  * specifier.
  561  *
  562  * After the call, the modified sds string is no longer valid and all the
  563  * references must be substituted with the new pointer returned by the call.
  564  *
  565  * Example:
  566  *
  567  * s = sdsnew("Sum is: ");
  568  * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b).
  569  *
  570  * Often you need to create a string from scratch with the printf-alike
  571  * format. When this is the need, just use sdsempty() as the target string:
  572  *
  573  * s = sdscatprintf(sdsempty(), "... your format ...", args);
  574  */
  575 sds sdscatprintf(sds s, const char *fmt, ...) {
  576     va_list ap;
  577     char *t;
  578     va_start(ap, fmt);
  579     t = sdscatvprintf(s,fmt,ap);
  580     va_end(ap);
  581     return t;
  582 }
  583 
  584 /* This function is similar to sdscatprintf, but much faster as it does
  585  * not rely on sprintf() family functions implemented by the libc that
  586  * are often very slow. Moreover directly handling the sds string as
  587  * new data is concatenated provides a performance improvement.
  588  *
  589  * However this function only handles an incompatible subset of printf-alike
  590  * format specifiers:
  591  *
  592  * %s - C String
  593  * %S - SDS string
  594  * %i - signed int
  595  * %I - 64 bit signed integer (long long, int64_t)
  596  * %u - unsigned int
  597  * %U - 64 bit unsigned integer (unsigned long long, uint64_t)
  598  * %% - Verbatim "%" character.
  599  */
  600 sds sdscatfmt(sds s, char const *fmt, ...) {
  601     size_t initlen = sdslen(s);
  602     const char *f = fmt;
  603     long i;
  604     va_list ap;
  605 
  606     va_start(ap,fmt);
  607     f = fmt;    /* Next format specifier byte to process. */
  608     i = initlen; /* Position of the next byte to write to dest str. */
  609     while(*f) {
  610         char next, *str;
  611         size_t l;
  612         long long num;
  613         unsigned long long unum;
  614 
  615         /* Make sure there is always space for at least 1 char. */
  616         if (sdsavail(s)==0) {
  617             s = sdsMakeRoomFor(s,1);
  618         }
  619 
  620         switch(*f) {
  621         case '%':
  622             next = *(f+1);
  623             f++;
  624             switch(next) {
  625             case 's':
  626             case 'S':
  627                 str = va_arg(ap,char*);
  628                 l = (next == 's') ? strlen(str) : sdslen(str);
  629                 if (sdsavail(s) < l) {
  630                     s = sdsMakeRoomFor(s,l);
  631                 }
  632                 memcpy(s+i,str,l);
  633                 sdsinclen(s,l);
  634                 i += l;
  635                 break;
  636             case 'i':
  637             case 'I':
  638                 if (next == 'i')
  639                     num = va_arg(ap,int);
  640                 else
  641                     num = va_arg(ap,long long);
  642                 {
  643                     char buf[SDS_LLSTR_SIZE];
  644                     l = sdsll2str(buf,num);
  645                     if (sdsavail(s) < l) {
  646                         s = sdsMakeRoomFor(s,l);
  647                     }
  648                     memcpy(s+i,buf,l);
  649                     sdsinclen(s,l);
  650                     i += l;
  651                 }
  652                 break;
  653             case 'u':
  654             case 'U':
  655                 if (next == 'u')
  656                     unum = va_arg(ap,unsigned int);
  657                 else
  658                     unum = va_arg(ap,unsigned long long);
  659                 {
  660                     char buf[SDS_LLSTR_SIZE];
  661                     l = sdsull2str(buf,unum);
  662                     if (sdsavail(s) < l) {
  663                         s = sdsMakeRoomFor(s,l);
  664                     }
  665                     memcpy(s+i,buf,l);
  666                     sdsinclen(s,l);
  667                     i += l;
  668                 }
  669                 break;
  670             default: /* Handle %% and generally %<unknown>. */
  671                 s[i++] = next;
  672                 sdsinclen(s,1);
  673                 break;
  674             }
  675             break;
  676         default:
  677             s[i++] = *f;
  678             sdsinclen(s,1);
  679             break;
  680         }
  681         f++;
  682     }
  683     va_end(ap);
  684 
  685     /* Add null-term */
  686     s[i] = '\0';
  687     return s;
  688 }
  689 
  690 /* Remove the part of the string from left and from right composed just of
  691  * contiguous characters found in 'cset', that is a null terminted C string.
  692  *
  693  * After the call, the modified sds string is no longer valid and all the
  694  * references must be substituted with the new pointer returned by the call.
  695  *
  696  * Example:
  697  *
  698  * s = sdsnew("AA...AA.a.aa.aHelloWorld     :::");
  699  * s = sdstrim(s,"Aa. :");
  700  * printf("%s\n", s);
  701  *
  702  * Output will be just "HelloWorld".
  703  */
  704 sds sdstrim(sds s, const char *cset) {
  705     char *start, *end, *sp, *ep;
  706     size_t len;
  707 
  708     sp = start = s;
  709     ep = end = s+sdslen(s)-1;
  710     while(sp <= end && strchr(cset, *sp)) sp++;
  711     while(ep > sp && strchr(cset, *ep)) ep--;
  712     len = (sp > ep) ? 0 : ((ep-sp)+1);
  713     if (s != sp) memmove(s, sp, len);
  714     s[len] = '\0';
  715     sdssetlen(s,len);
  716     return s;
  717 }
  718 
  719 /* Turn the string into a smaller (or equal) string containing only the
  720  * substring specified by the 'start' and 'end' indexes.
  721  *
  722  * start and end can be negative, where -1 means the last character of the
  723  * string, -2 the penultimate character, and so forth.
  724  *
  725  * The interval is inclusive, so the start and end characters will be part
  726  * of the resulting string.
  727  *
  728  * The string is modified in-place.
  729  *
  730  * Example:
  731  *
  732  * s = sdsnew("Hello World");
  733  * sdsrange(s,1,-1); => "ello World"
  734  */
  735 void sdsrange(sds s, ssize_t start, ssize_t end) {
  736     size_t newlen, len = sdslen(s);
  737 
  738     if (len == 0) return;
  739     if (start < 0) {
  740         start = len+start;
  741         if (start < 0) start = 0;
  742     }
  743     if (end < 0) {
  744         end = len+end;
  745         if (end < 0) end = 0;
  746     }
  747     newlen = (start > end) ? 0 : (end-start)+1;
  748     if (newlen != 0) {
  749         if (start >= (ssize_t)len) {
  750             newlen = 0;
  751         } else if (end >= (ssize_t)len) {
  752             end = len-1;
  753             newlen = (start > end) ? 0 : (end-start)+1;
  754         }
  755     } else {
  756         start = 0;
  757     }
  758     if (start && newlen) memmove(s, s+start, newlen);
  759     s[newlen] = 0;
  760     sdssetlen(s,newlen);
  761 }
  762 
  763 /* Apply tolower() to every character of the sds string 's'. */
  764 void sdstolower(sds s) {
  765     size_t len = sdslen(s), j;
  766 
  767     for (j = 0; j < len; j++) s[j] = tolower(s[j]);
  768 }
  769 
  770 /* Apply toupper() to every character of the sds string 's'. */
  771 void sdstoupper(sds s) {
  772     size_t len = sdslen(s), j;
  773 
  774     for (j = 0; j < len; j++) s[j] = toupper(s[j]);
  775 }
  776 
  777 /* Compare two sds strings s1 and s2 with memcmp().
  778  *
  779  * Return value:
  780  *
  781  *     positive if s1 > s2.
  782  *     negative if s1 < s2.
  783  *     0 if s1 and s2 are exactly the same binary string.
  784  *
  785  * If two strings share exactly the same prefix, but one of the two has
  786  * additional characters, the longer string is considered to be greater than
  787  * the smaller one. */
  788 int sdscmp(const sds s1, const sds s2) {
  789     size_t l1, l2, minlen;
  790     int cmp;
  791 
  792     l1 = sdslen(s1);
  793     l2 = sdslen(s2);
  794     minlen = (l1 < l2) ? l1 : l2;
  795     cmp = memcmp(s1,s2,minlen);
  796     if (cmp == 0) return l1>l2? 1: (l1<l2? -1: 0);
  797     return cmp;
  798 }
  799 
  800 /* Split 's' with separator in 'sep'. An array
  801  * of sds strings is returned. *count will be set
  802  * by reference to the number of tokens returned.
  803  *
  804  * On out of memory, zero length string, zero length
  805  * separator, NULL is returned.
  806  *
  807  * Note that 'sep' is able to split a string using
  808  * a multi-character separator. For example
  809  * sdssplit("foo_-_bar","_-_"); will return two
  810  * elements "foo" and "bar".
  811  *
  812  * This version of the function is binary-safe but
  813  * requires length arguments. sdssplit() is just the
  814  * same function but for zero-terminated strings.
  815  */
  816 sds *sdssplitlen(const char *s, ssize_t len, const char *sep, int seplen, int *count) {
  817     int elements = 0, slots = 5;
  818     long start = 0, j;
  819     sds *tokens;
  820 
  821     if (seplen < 1 || len < 0) return NULL;
  822 
  823     tokens = s_malloc(sizeof(sds)*slots);
  824     if (tokens == NULL) return NULL;
  825 
  826     if (len == 0) {
  827         *count = 0;
  828         return tokens;
  829     }
  830     for (j = 0; j < (len-(seplen-1)); j++) {
  831         /* make sure there is room for the next element and the final one */
  832         if (slots < elements+2) {
  833             sds *newtokens;
  834 
  835             slots *= 2;
  836             newtokens = s_realloc(tokens,sizeof(sds)*slots);
  837             if (newtokens == NULL) goto cleanup;
  838             tokens = newtokens;
  839         }
  840         /* search the separator */
  841         if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0)) {
  842             tokens[elements] = sdsnewlen(s+start,j-start);
  843             if (tokens[elements] == NULL) goto cleanup;
  844             elements++;
  845             start = j+seplen;
  846             j = j+seplen-1; /* skip the separator */
  847         }
  848     }
  849     /* Add the final element. We are sure there is room in the tokens array. */
  850     tokens[elements] = sdsnewlen(s+start,len-start);
  851     if (tokens[elements] == NULL) goto cleanup;
  852     elements++;
  853     *count = elements;
  854     return tokens;
  855 
  856 cleanup:
  857     {
  858         int i;
  859         for (i = 0; i < elements; i++) sdsfree(tokens[i]);
  860         s_free(tokens);
  861         *count = 0;
  862         return NULL;
  863     }
  864 }
  865 
  866 /* Free the result returned by sdssplitlen(), or do nothing if 'tokens' is NULL. */
  867 void sdsfreesplitres(sds *tokens, int count) {
  868     if (!tokens) return;
  869     while(count--)
  870         sdsfree(tokens[count]);
  871     s_free(tokens);
  872 }
  873 
  874 /* Append to the sds string "s" an escaped string representation where
  875  * all the non-printable characters (tested with isprint()) are turned into
  876  * escapes in the form "\n\r\a...." or "\x<hex-number>".
  877  *
  878  * After the call, the modified sds string is no longer valid and all the
  879  * references must be substituted with the new pointer returned by the call. */
  880 sds sdscatrepr(sds s, const char *p, size_t len) {
  881     s = sdscatlen(s,"\"",1);
  882     while(len--) {
  883         switch(*p) {
  884         case '\\':
  885         case '"':
  886             s = sdscatprintf(s,"\\%c",*p);
  887             break;
  888         case '\n': s = sdscatlen(s,"\\n",2); break;
  889         case '\r': s = sdscatlen(s,"\\r",2); break;
  890         case '\t': s = sdscatlen(s,"\\t",2); break;
  891         case '\a': s = sdscatlen(s,"\\a",2); break;
  892         case '\b': s = sdscatlen(s,"\\b",2); break;
  893         default:
  894             if (isprint(*p))
  895                 s = sdscatprintf(s,"%c",*p);
  896             else
  897                 s = sdscatprintf(s,"\\x%02x",(unsigned char)*p);
  898             break;
  899         }
  900         p++;
  901     }
  902     return sdscatlen(s,"\"",1);
  903 }
  904 
  905 /* Helper function for sdssplitargs() that returns non zero if 'c'
  906  * is a valid hex digit. */
  907 int is_hex_digit(char c) {
  908     return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
  909            (c >= 'A' && c <= 'F');
  910 }
  911 
  912 /* Helper function for sdssplitargs() that converts a hex digit into an
  913  * integer from 0 to 15 */
  914 int hex_digit_to_int(char c) {
  915     switch(c) {
  916     case '0': return 0;
  917     case '1': return 1;
  918     case '2': return 2;
  919     case '3': return 3;
  920     case '4': return 4;
  921     case '5': return 5;
  922     case '6': return 6;
  923     case '7': return 7;
  924     case '8': return 8;
  925     case '9': return 9;
  926     case 'a': case 'A': return 10;
  927     case 'b': case 'B': return 11;
  928     case 'c': case 'C': return 12;
  929     case 'd': case 'D': return 13;
  930     case 'e': case 'E': return 14;
  931     case 'f': case 'F': return 15;
  932     default: return 0;
  933     }
  934 }
  935 
  936 /* Split a line into arguments, where every argument can be in the
  937  * following programming-language REPL-alike form:
  938  *
  939  * foo bar "newline are supported\n" and "\xff\x00otherstuff"
  940  *
  941  * The number of arguments is stored into *argc, and an array
  942  * of sds is returned.
  943  *
  944  * The caller should free the resulting array of sds strings with
  945  * sdsfreesplitres().
  946  *
  947  * Note that sdscatrepr() is able to convert back a string into
  948  * a quoted string in the same format sdssplitargs() is able to parse.
  949  *
  950  * The function returns the allocated tokens on success, even when the
  951  * input string is empty, or NULL if the input contains unbalanced
  952  * quotes or closed quotes followed by non space characters
  953  * as in: "foo"bar or "foo'
  954  */
  955 sds *sdssplitargs(const char *line, int *argc) {
  956     const char *p = line;
  957     char *current = NULL;
  958     char **vector = NULL;
  959 
  960     *argc = 0;
  961     while(1) {
  962         /* skip blanks */
  963         while(*p && isspace(*p)) p++;
  964         if (*p) {
  965             /* get a token */
  966             int inq=0;  /* set to 1 if we are in "quotes" */
  967             int insq=0; /* set to 1 if we are in 'single quotes' */
  968             int done=0;
  969 
  970             if (current == NULL) current = sdsempty();
  971             while(!done) {
  972                 if (inq) {
  973                     if (*p == '\\' && *(p+1) == 'x' &&
  974                                              is_hex_digit(*(p+2)) &&
  975                                              is_hex_digit(*(p+3)))
  976                     {
  977                         unsigned char byte;
  978 
  979                         byte = (hex_digit_to_int(*(p+2))*16)+
  980                                 hex_digit_to_int(*(p+3));
  981                         current = sdscatlen(current,(char*)&byte,1);
  982                         p += 3;
  983                     } else if (*p == '\\' && *(p+1)) {
  984                         char c;
  985 
  986                         p++;
  987                         switch(*p) {
  988                         case 'n': c = '\n'; break;
  989                         case 'r': c = '\r'; break;
  990                         case 't': c = '\t'; break;
  991                         case 'b': c = '\b'; break;
  992                         case 'a': c = '\a'; break;
  993                         default: c = *p; break;
  994                         }
  995                         current = sdscatlen(current,&c,1);
  996                     } else if (*p == '"') {
  997                         /* closing quote must be followed by a space or
  998                          * nothing at all. */
  999                         if (*(p+1) && !isspace(*(p+1))) goto err;
 1000                         done=1;
 1001                     } else if (!*p) {
 1002                         /* unterminated quotes */
 1003                         goto err;
 1004                     } else {
 1005                         current = sdscatlen(current,p,1);
 1006                     }
 1007                 } else if (insq) {
 1008                     if (*p == '\\' && *(p+1) == '\'') {
 1009                         p++;
 1010                         current = sdscatlen(current,"'",1);
 1011                     } else if (*p == '\'') {
 1012                         /* closing quote must be followed by a space or
 1013                          * nothing at all. */
 1014                         if (*(p+1) && !isspace(*(p+1))) goto err;
 1015                         done=1;
 1016                     } else if (!*p) {
 1017                         /* unterminated quotes */
 1018                         goto err;
 1019                     } else {
 1020                         current = sdscatlen(current,p,1);
 1021                     }
 1022                 } else {
 1023                     switch(*p) {
 1024                     case ' ':
 1025                     case '\n':
 1026                     case '\r':
 1027                     case '\t':
 1028                     case '\0':
 1029                         done=1;
 1030                         break;
 1031                     case '"':
 1032                         inq=1;
 1033                         break;
 1034                     case '\'':
 1035                         insq=1;
 1036                         break;
 1037                     default:
 1038                         current = sdscatlen(current,p,1);
 1039                         break;
 1040                     }
 1041                 }
 1042                 if (*p) p++;
 1043             }
 1044             /* add the token to the vector */
 1045             vector = s_realloc(vector,((*argc)+1)*sizeof(char*));
 1046             vector[*argc] = current;
 1047             (*argc)++;
 1048             current = NULL;
 1049         } else {
 1050             /* Even on empty input string return something not NULL. */
 1051             if (vector == NULL) vector = s_malloc(sizeof(void*));
 1052             return vector;
 1053         }
 1054     }
 1055 
 1056 err:
 1057     while((*argc)--)
 1058         sdsfree(vector[*argc]);
 1059     s_free(vector);
 1060     if (current) sdsfree(current);
 1061     *argc = 0;
 1062     return NULL;
 1063 }
 1064 
 1065 /* Modify the string substituting all the occurrences of the set of
 1066  * characters specified in the 'from' string to the corresponding character
 1067  * in the 'to' array.
 1068  *
 1069  * For instance: sdsmapchars(mystring, "ho", "01", 2)
 1070  * will have the effect of turning the string "hello" into "0ell1".
 1071  *
 1072  * The function returns the sds string pointer, that is always the same
 1073  * as the input pointer since no resize is needed. */
 1074 sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
 1075     size_t j, i, l = sdslen(s);
 1076 
 1077     for (j = 0; j < l; j++) {
 1078         for (i = 0; i < setlen; i++) {
 1079             if (s[j] == from[i]) {
 1080                 s[j] = to[i];
 1081                 break;
 1082             }
 1083         }
 1084     }
 1085     return s;
 1086 }
 1087 
 1088 /* Join an array of C strings using the specified separator (also a C string).
 1089  * Returns the result as an sds string. */
 1090 sds sdsjoin(char **argv, int argc, char *sep) {
 1091     sds join = sdsempty();
 1092     int j;
 1093 
 1094     for (j = 0; j < argc; j++) {
 1095         join = sdscat(join, argv[j]);
 1096         if (j != argc-1) join = sdscat(join,sep);
 1097     }
 1098     return join;
 1099 }
 1100 
 1101 /* Like sdsjoin, but joins an array of SDS strings. */
 1102 sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen) {
 1103     sds join = sdsempty();
 1104     int j;
 1105 
 1106     for (j = 0; j < argc; j++) {
 1107         join = sdscatsds(join, argv[j]);
 1108         if (j != argc-1) join = sdscatlen(join,sep,seplen);
 1109     }
 1110     return join;
 1111 }
 1112 
 1113 /* Wrappers to the allocators used by SDS. Note that SDS will actually
 1114  * just use the macros defined into sdsalloc.h in order to avoid to pay
 1115  * the overhead of function calls. Here we define these wrappers only for
 1116  * the programs SDS is linked to, if they want to touch the SDS internals
 1117  * even if they use a different allocator. */
 1118 void *sds_malloc(size_t size) { return s_malloc(size); }
 1119 void *sds_realloc(void *ptr, size_t size) { return s_realloc(ptr,size); }
 1120 void sds_free(void *ptr) { s_free(ptr); }
 1121 
 1122 #if defined(SDS_TEST_MAIN)
 1123 #include <stdio.h>
 1124 #include "testhelp.h"
 1125 #include "limits.h"
 1126 
 1127 #define UNUSED(x) (void)(x)
 1128 int sdsTest(void) {
 1129     {
 1130         sds x = sdsnew("foo"), y;
 1131 
 1132         test_cond("Create a string and obtain the length",
 1133             sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0)
 1134 
 1135         sdsfree(x);
 1136         x = sdsnewlen("foo",2);
 1137         test_cond("Create a string with specified length",
 1138             sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0)
 1139 
 1140         x = sdscat(x,"bar");
 1141         test_cond("Strings concatenation",
 1142             sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0);
 1143 
 1144         x = sdscpy(x,"a");
 1145         test_cond("sdscpy() against an originally longer string",
 1146             sdslen(x) == 1 && memcmp(x,"a\0",2) == 0)
 1147 
 1148         x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk");
 1149         test_cond("sdscpy() against an originally shorter string",
 1150             sdslen(x) == 33 &&
 1151             memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0)
 1152 
 1153         sdsfree(x);
 1154         x = sdscatprintf(sdsempty(),"%d",123);
 1155         test_cond("sdscatprintf() seems working in the base case",
 1156             sdslen(x) == 3 && memcmp(x,"123\0",4) == 0)
 1157 
 1158         sdsfree(x);
 1159         x = sdsnew("--");
 1160         x = sdscatfmt(x, "Hello %s World %I,%I--", "Hi!", LLONG_MIN,LLONG_MAX);
 1161         test_cond("sdscatfmt() seems working in the base case",
 1162             sdslen(x) == 60 &&
 1163             memcmp(x,"--Hello Hi! World -9223372036854775808,"
 1164                      "9223372036854775807--",60) == 0)
 1165         printf("[%s]\n",x);
 1166 
 1167         sdsfree(x);
 1168         x = sdsnew("--");
 1169         x = sdscatfmt(x, "%u,%U--", UINT_MAX, ULLONG_MAX);
 1170         test_cond("sdscatfmt() seems working with unsigned numbers",
 1171             sdslen(x) == 35 &&
 1172             memcmp(x,"--4294967295,18446744073709551615--",35) == 0)
 1173 
 1174         sdsfree(x);
 1175         x = sdsnew(" x ");
 1176         sdstrim(x," x");
 1177         test_cond("sdstrim() works when all chars match",
 1178             sdslen(x) == 0)
 1179 
 1180         sdsfree(x);
 1181         x = sdsnew(" x ");
 1182         sdstrim(x," ");
 1183         test_cond("sdstrim() works when a single char remains",
 1184             sdslen(x) == 1 && x[0] == 'x')
 1185 
 1186         sdsfree(x);
 1187         x = sdsnew("xxciaoyyy");
 1188         sdstrim(x,"xy");
 1189         test_cond("sdstrim() correctly trims characters",
 1190             sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0)
 1191 
 1192         y = sdsdup(x);
 1193         sdsrange(y,1,1);
 1194         test_cond("sdsrange(...,1,1)",
 1195             sdslen(y) == 1 && memcmp(y,"i\0",2) == 0)
 1196 
 1197         sdsfree(y);
 1198         y = sdsdup(x);
 1199         sdsrange(y,1,-1);
 1200         test_cond("sdsrange(...,1,-1)",
 1201             sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
 1202 
 1203         sdsfree(y);
 1204         y = sdsdup(x);
 1205         sdsrange(y,-2,-1);
 1206         test_cond("sdsrange(...,-2,-1)",
 1207             sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0)
 1208 
 1209         sdsfree(y);
 1210         y = sdsdup(x);
 1211         sdsrange(y,2,1);
 1212         test_cond("sdsrange(...,2,1)",
 1213             sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
 1214 
 1215         sdsfree(y);
 1216         y = sdsdup(x);
 1217         sdsrange(y,1,100);
 1218         test_cond("sdsrange(...,1,100)",
 1219             sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
 1220 
 1221         sdsfree(y);
 1222         y = sdsdup(x);
 1223         sdsrange(y,100,100);
 1224         test_cond("sdsrange(...,100,100)",
 1225             sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
 1226 
 1227         sdsfree(y);
 1228         sdsfree(x);
 1229         x = sdsnew("foo");
 1230         y = sdsnew("foa");
 1231         test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0)
 1232 
 1233         sdsfree(y);
 1234         sdsfree(x);
 1235         x = sdsnew("bar");
 1236         y = sdsnew("bar");
 1237         test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0)
 1238 
 1239         sdsfree(y);
 1240         sdsfree(x);
 1241         x = sdsnew("aar");
 1242         y = sdsnew("bar");
 1243         test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0)
 1244 
 1245         sdsfree(y);
 1246         sdsfree(x);
 1247         x = sdsnewlen("\a\n\0foo\r",7);
 1248         y = sdscatrepr(sdsempty(),x,sdslen(x));
 1249         test_cond("sdscatrepr(...data...)",
 1250             memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0)
 1251 
 1252         {
 1253             unsigned int oldfree;
 1254             char *p;
 1255             int step = 10, j, i;
 1256 
 1257             sdsfree(x);
 1258             sdsfree(y);
 1259             x = sdsnew("0");
 1260             test_cond("sdsnew() free/len buffers", sdslen(x) == 1 && sdsavail(x) == 0);
 1261 
 1262             /* Run the test a few times in order to hit the first two
 1263              * SDS header types. */
 1264             for (i = 0; i < 10; i++) {
 1265                 int oldlen = sdslen(x);
 1266                 x = sdsMakeRoomFor(x,step);
 1267                 int type = x[-1]&SDS_TYPE_MASK;
 1268 
 1269                 test_cond("sdsMakeRoomFor() len", sdslen(x) == oldlen);
 1270                 if (type != SDS_TYPE_5) {
 1271                     test_cond("sdsMakeRoomFor() free", sdsavail(x) >= step);
 1272                     oldfree = sdsavail(x);
 1273                 }
 1274                 p = x+oldlen;
 1275                 for (j = 0; j < step; j++) {
 1276                     p[j] = 'A'+j;
 1277                 }
 1278                 sdsIncrLen(x,step);
 1279             }
 1280             test_cond("sdsMakeRoomFor() content",
 1281                 memcmp("0ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ",x,101) == 0);
 1282             test_cond("sdsMakeRoomFor() final length",sdslen(x)==101);
 1283 
 1284             sdsfree(x);
 1285         }
 1286     }
 1287     test_report()
 1288     return 0;
 1289 }
 1290 #endif
 1291 
 1292 #ifdef SDS_TEST_MAIN
 1293 int main(void) {
 1294     return sdsTest();
 1295 }
 1296 #endif