1 /* SDS (Simple Dynamic Strings), A C dynamic strings library.
3 * Copyright (c) 2006-2014, Salvatore Sanfilippo <antirez at gmail dot com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * * Neither the name of Redis nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without
16 * specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
39 typedef struct sdshdr_
{
45 static INLINE sdshdr
*sds_start(const sds s
)
47 return (sdshdr
*) (s
-(int)offsetof(sdshdr
, buf
));
50 /* Create a new sds string with the content specified by the 'init' pointer
52 * If NULL is used for 'init' the string is initialized with zero bytes.
54 * The string is always null-termined (all the sds strings are, always) so
55 * even if you create an sds string with:
57 * mystring = sdsnewlen("abc",3");
59 * You can print the string with printf() as there is an implicit \0 at the
60 * end of the string. However the string is binary safe and can contain
61 * \0 characters in the middle, as the length is stored in the sds header. */
62 sds
sdsnewlen(const void *init
, size_t initlen
) {
66 sh
= (sdshdr
*) malloc(sizeof *sh
+initlen
+1);
68 sh
= (sdshdr
*) calloc(sizeof *sh
+initlen
+1,1);
70 if (sh
== NULL
) return NULL
;
74 memcpy(sh
->buf
, init
, initlen
);
75 sh
->buf
[initlen
] = '\0';
76 return (char*)sh
->buf
;
79 /* Create an empty (zero length) sds string. Even in this case the string
80 * always has an implicit null term. */
82 return sdsnewlen("",0);
85 /* Create a new sds string starting from a null termined C string. */
86 sds
sdsnew(const char *init
) {
87 size_t initlen
= (init
== NULL
) ? 0 : strlen(init
);
88 return sdsnewlen(init
, initlen
);
91 /* Duplicate an sds string. */
92 sds
sdsdup(const sds s
) {
93 return sdsnewlen(s
, sdslen(s
));
96 /* Free an sds string. No operation is performed if 's' is NULL. */
98 if (s
== NULL
) return;
103 /* Set the sds string length to the length as obtained with strlen(), so
104 * considering as content only up to the first null term character.
106 * This function is useful when the sds string is hacked manually in some
107 * way, like in the following example:
109 * s = sdsnew("foobar");
112 * printf("%d\n", sdslen(s));
114 * The output will be "2", but if we comment out the call to sdsupdatelen()
115 * the output will be "6" as the string was modified but the logical length
116 * remains 6 bytes. */
117 void sdsupdatelen(sds s
) {
118 if (s
== NULL
) return;
120 sdshdr
*sh
= sds_start(s
);
121 size_t reallen
= strlen(s
);
122 sh
->free
+= (sh
->len
-reallen
);
126 /* Modify an sds string on-place to make it empty (zero length).
127 * However all the existing buffer is not discarded but set as free space
128 * so that next append operations will not require allocations up to the
129 * number of bytes previously available. */
130 void sdsclear(sds s
) {
131 if (s
== NULL
) return;
133 sdshdr
*sh
= sds_start(s
);
139 /* Enlarge the free space at the end of the sds string so that the caller
140 * is sure that after calling this function can overwrite up to addlen
141 * bytes after the end of the string, plus one more byte for nul term.
143 * Note: this does not change the *length* of the sds string as returned
144 * by sdslen(), but only the free buffer space we have. */
145 sds
sdsMakeRoomFor(sds s
, size_t addlen
) {
146 if (s
== NULL
) return NULL
;
149 size_t free
= sdsavail(s
);
152 if (free
>= addlen
) return s
;
155 newlen
= (len
+addlen
);
156 if (newlen
< SDS_MAX_PREALLOC
)
159 newlen
+= SDS_MAX_PREALLOC
;
160 newsh
= (sdshdr
*) realloc(sh
, sizeof *newsh
+newlen
+1);
161 if (newsh
== NULL
) return NULL
;
163 newsh
->free
= newlen
- len
;
167 /* Reallocate the sds string so that it has no free space at the end. The
168 * contained string remains not altered, but next concatenation operations
169 * will require a reallocation.
171 * After the call, the passed sds string is no longer valid and all the
172 * references must be substituted with the new pointer returned by the call. */
173 sds
sdsRemoveFreeSpace(sds s
) {
174 if (s
== NULL
) return NULL
;
179 newsh
= (sdshdr
*) realloc(sh
, sizeof *sh
+sh
->len
+1);
180 if (newsh
== NULL
) return NULL
;
186 /* Return the total size of the allocation of the specifed sds string,
188 * 1) The sds header before the pointer.
190 * 3) The free buffer at the end if any.
191 * 4) The implicit null term.
193 size_t sdsAllocSize(sds s
) {
194 if (s
== NULL
) return 0;
196 sdshdr
*sh
= sds_start(s
);
198 return sizeof(*sh
)+sh
->len
+sh
->free
+1;
201 /* Increment the sds length and decrements the left free space at the
202 * end of the string according to 'incr'. Also set the null term
203 * in the new end of the string.
205 * This function is used in order to fix the string length after the
206 * user calls sdsMakeRoomFor(), writes something after the end of
207 * the current string, and finally needs to set the new length.
209 * Note: it is possible to use a negative increment in order to
210 * right-trim the string.
214 * Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the
215 * following schema, to cat bytes coming from the kernel to the end of an
216 * sds string without copying into an intermediate buffer:
218 * oldlen = sdslen(s);
219 * s = sdsMakeRoomFor(s, BUFFER_SIZE);
220 * nread = read(fd, s+oldlen, BUFFER_SIZE);
221 * ... check for nread <= 0 and handle it ...
222 * sdsIncrLen(s, nread);
224 void sdsIncrLen(sds s
, int incr
) {
225 if (s
== NULL
) return;
227 sdshdr
*sh
= sds_start(s
);
230 size_t tmp
= (size_t)(incr
);
231 assert(sh
->free
>= tmp
);
236 size_t tmp
= (size_t)(-incr
);
237 assert(sh
->len
>= tmp
);
244 /* Grow the sds to have the specified length. Bytes that were not part of
245 * the original length of the sds will be set to zero.
247 * if the specified length is smaller than the current length, no operation
249 sds
sdsgrowzero(sds s
, size_t len
) {
250 if (s
== NULL
) return NULL
;
252 sdshdr
*sh
= sds_start(s
);
253 size_t totlen
, curlen
= sh
->len
;
255 if (len
<= curlen
) return s
;
256 s
= sdsMakeRoomFor(s
,len
-curlen
);
257 if (s
== NULL
) return NULL
;
259 /* Make sure added region doesn't contain garbage */
261 memset(s
+curlen
,0,(len
-curlen
+1)); /* also set trailing \0 byte */
262 totlen
= sh
->len
+sh
->free
;
264 sh
->free
= totlen
-sh
->len
;
268 /* Append the specified binary-safe string pointed by 't' of 'len' bytes to the
269 * end of the specified sds string 's'.
271 * After the call, the passed sds string is no longer valid and all the
272 * references must be substituted with the new pointer returned by the call. */
273 sds
sdscatlen(sds s
, const void *t
, size_t len
) {
275 size_t curlen
= sdslen(s
);
277 s
= sdsMakeRoomFor(s
,len
);
278 if (s
== NULL
) return NULL
;
280 memcpy(s
+curlen
, t
, len
);
281 sh
->len
= curlen
+len
;
282 sh
->free
= sh
->free
-len
;
283 s
[curlen
+len
] = '\0';
287 /* Append the specified null termianted C string to the sds string 's'.
289 * After the call, the passed sds string is no longer valid and all the
290 * references must be substituted with the new pointer returned by the call. */
291 sds
sdscat(sds s
, const char *t
) {
292 return sdscatlen(s
, t
, strlen(t
));
295 /* Append the specified sds 't' to the existing sds 's'.
297 * After the call, the modified sds string is no longer valid and all the
298 * references must be substituted with the new pointer returned by the call. */
299 sds
sdscatsds(sds s
, const sds t
) {
300 return sdscatlen(s
, t
, sdslen(t
));
303 /* Destructively modify the sds string 's' to hold the specified binary
304 * safe string pointed by 't' of length 'len' bytes. */
305 sds
sdscpylen(sds s
, const char *t
, size_t len
) {
306 if (s
== NULL
) return NULL
;
308 sdshdr
*sh
= sds_start(s
);
309 size_t totlen
= sh
->free
+sh
->len
;
312 s
= sdsMakeRoomFor(s
,len
-sh
->len
);
313 if (s
== NULL
) return NULL
;
315 totlen
= sh
->free
+sh
->len
;
320 sh
->free
= totlen
-len
;
324 /* Like sdscpylen() but 't' must be a null-termined string so that the length
325 * of the string is obtained with strlen(). */
326 sds
sdscpy(sds s
, const char *t
) {
327 return sdscpylen(s
, t
, strlen(t
));
330 /* Like sdscatpritf() but gets va_list instead of being variadic. */
331 sds
sdscatvprintf(sds s
, const char *fmt
, va_list ap
) {
337 buf
= (char*) malloc(buflen
);
338 if (buf
== NULL
) return NULL
;
339 buf
[buflen
-2] = '\0';
341 vsnprintf(buf
, buflen
, fmt
, cpy
);
343 if (buf
[buflen
-2] != '\0') {
355 /* Append to the sds string 's' a string obtained using printf-alike format
358 * After the call, the modified sds string is no longer valid and all the
359 * references must be substituted with the new pointer returned by the call.
363 * s = sdsempty("Sum is: ");
364 * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b).
366 * Often you need to create a string from scratch with the printf-alike
367 * format. When this is the need, just use sdsempty() as the target string:
369 * s = sdscatprintf(sdsempty(), "... your format ...", args);
371 sds
sdscatprintf(sds s
, const char *fmt
, ...) {
375 t
= sdscatvprintf(s
,fmt
,ap
);
380 /* Remove the part of the string from left and from right composed just of
381 * contiguous characters found in 'cset', that is a null terminted C string.
383 * After the call, the modified sds string is no longer valid and all the
384 * references must be substituted with the new pointer returned by the call.
388 * s = sdsnew("AA...AA.a.aa.aHello World :::");
389 * sdstrim(s,"aA. :");
392 * Output will be just "Hello World".
394 void sdstrim(sds s
, const char *cset
) {
395 if (s
== NULL
) return;
397 sdshdr
*sh
= sds_start(s
);
398 char *start
, *end
, *sp
, *ep
;
402 ep
= end
= s
+sdslen(s
)-1;
403 while(sp
<= end
&& strchr(cset
, *sp
)) sp
++;
404 while(ep
> start
&& strchr(cset
, *ep
)) ep
--;
405 len
= (sp
> ep
) ? 0 : (size_t)((ep
-sp
)+1);
406 if (sh
->buf
!= sp
) memmove(sh
->buf
, sp
, len
);
408 sh
->free
= sh
->free
+(sh
->len
-len
);
412 /* Turn the string into a smaller (or equal) string containing only the
413 * substring specified by the 'start' and 'end' indexes.
415 * start and end can be negative, where -1 means the last character of the
416 * string, -2 the penultimate character, and so forth.
418 * The interval is inclusive, so the start and end characters will be part
419 * of the resulting string.
421 * The string is modified in-place.
425 * s = sdsnew("Hello World");
426 * sdsrange(s,1,-1); => "ello World"
428 void sdsrange(sds s
, int start
, int end
) {
429 sdshdr
*sh
= sds_start(s
);
430 size_t newlen
, len
= sdslen(s
);
432 if (len
== 0) return;
434 start
= (int)len
+start
;
435 if (start
< 0) start
= 0;
439 if (end
< -1) end
= -1;
441 newlen
= (start
> end
) ? 0 : (size_t)((end
-start
)+1);
443 if (start
>= (signed)len
) {
445 } else if (end
>= (signed)len
) {
447 newlen
= (start
> end
) ? 0 : (size_t)((end
-start
)+1);
452 if (start
&& newlen
) memmove(sh
->buf
, sh
->buf
+start
, newlen
);
454 sh
->free
= sh
->free
+(sh
->len
-newlen
);
458 /* Apply tolower() to every character of the sds string 's'. */
459 void sdstolower(sds s
) {
460 size_t len
= sdslen(s
), j
;
462 for (j
= 0; j
< len
; j
++) s
[j
] = (char)tolower((unsigned char)s
[j
]);
465 /* Apply toupper() to every character of the sds string 's'. */
466 void sdstoupper(sds s
) {
467 size_t len
= sdslen(s
), j
;
469 for (j
= 0; j
< len
; j
++) s
[j
] = (char)toupper((unsigned char)s
[j
]);
472 /* Compare two sds strings s1 and s2 with memcmp().
478 * 0 if s1 and s2 are exactly the same binary string.
480 * If two strings share exactly the same prefix, but one of the two has
481 * additional characters, the longer string is considered to be greater than
482 * the smaller one. */
483 int sdscmp(const sds s1
, const sds s2
) {
484 size_t l1
, l2
, minlen
;
489 minlen
= (l1
< l2
) ? l1
: l2
;
490 cmp
= memcmp(s1
,s2
,minlen
);
492 int diff
= (int)l1
- (int)l2
;
493 /* https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign */
494 return (diff
> 0) - (diff
< 0);
499 /* Split 's' with separator in 'sep'. An array
500 * of sds strings is returned. *count will be set
501 * by reference to the number of tokens returned.
503 * On out of memory, zero length string, zero length
504 * separator, NULL is returned.
506 * Note that 'sep' is able to split a string using
507 * a multi-character separator. For example
508 * sdssplit("foo_-_bar","_-_"); will return two
509 * elements "foo" and "bar".
511 * This version of the function is binary-safe but
512 * requires length arguments. sdssplit() is just the
513 * same function but for zero-terminated strings.
515 sds
*sdssplitlen(const char *s
, int len
, const char *sep
, int seplen
, int *count
) {
516 size_t elements
= 0, slots
= 5, start
= 0, j
;
517 size_t len_
, seplen_
;
520 if (seplen
< 1 || len
< 0) return NULL
;
523 seplen_
= (size_t)seplen
;
525 tokens
= (sds
*) malloc(sizeof(sds
)*slots
);
526 if (tokens
== NULL
) return NULL
;
532 for (j
= 0; j
< (len_
-(seplen_
-1)); j
++) {
533 /* make sure there is room for the next element and the final one */
534 if (slots
< elements
+2) {
538 newtokens
= (sds
*) realloc(tokens
,sizeof(sds
)*slots
);
539 if (newtokens
== NULL
) goto cleanup
;
542 /* search the separator */
543 if ((seplen_
== 1 && *(s
+j
) == sep
[0]) || (memcmp(s
+j
,sep
,seplen_
) == 0)) {
544 tokens
[elements
] = sdsnewlen(s
+start
,j
-start
);
545 if (tokens
[elements
] == NULL
) goto cleanup
;
548 j
= j
+seplen_
-1; /* skip the separator */
551 /* Add the final element. We are sure there is room in the tokens array. */
552 tokens
[elements
] = sdsnewlen(s
+start
,len_
-start
);
553 if (tokens
[elements
] == NULL
) goto cleanup
;
555 *count
= (int)elements
;
561 for (i
= 0; i
< elements
; i
++) sdsfree(tokens
[i
]);
568 /* Free the result returned by sdssplitlen(), or do nothing if 'tokens' is NULL. */
569 void sdsfreesplitres(sds
*tokens
, int count
) {
572 sdsfree(tokens
[count
]);
576 /* Create an sds string from a long long value. It is much faster than:
578 * sdscatprintf(sdsempty(),"%lld\n", value);
580 sds
sdsfromlonglong(long long value
) {
582 unsigned long long v
;
584 v
= (unsigned long long)((value
< 0) ? (-value
) : value
);
585 p
= buf
+31; /* point to the last character */
590 if (value
< 0) *p
-- = '-';
592 return sdsnewlen(p
,(size_t)(32-(p
-buf
)));
595 /* Append to the sds string "s" an escaped string representation where
596 * all the non-printable characters (tested with isprint()) are turned into
597 * escapes in the form "\n\r\a...." or "\x<hex-number>".
599 * After the call, the modified sds string is no longer valid and all the
600 * references must be substituted with the new pointer returned by the call. */
601 sds
sdscatrepr(sds s
, const char *p
, size_t len
) {
602 s
= sdscatlen(s
,"\"",1);
607 s
= sdscatprintf(s
,"\\%c",*p
);
609 case '\n': s
= sdscatlen(s
,"\\n",2); break;
610 case '\r': s
= sdscatlen(s
,"\\r",2); break;
611 case '\t': s
= sdscatlen(s
,"\\t",2); break;
612 case '\a': s
= sdscatlen(s
,"\\a",2); break;
613 case '\b': s
= sdscatlen(s
,"\\b",2); break;
615 if (isprint((unsigned char)*p
))
616 s
= sdscatprintf(s
,"%c",*p
);
618 s
= sdscatprintf(s
,"\\x%02x",(unsigned char)*p
);
623 return sdscatlen(s
,"\"",1);
626 /* Helper function for sdssplitargs() that returns non zero if 'c'
627 * is a valid hex digit. */
628 static int is_hex_digit(char c
) {
629 return (c
>= '0' && c
<= '9') || (c
>= 'a' && c
<= 'f') ||
630 (c
>= 'A' && c
<= 'F');
633 /* Helper function for sdssplitargs() that converts a hex digit into an
634 * integer from 0 to 15 */
635 static int hex_digit_to_int(char c
) {
647 case 'a': case 'A': return 10;
648 case 'b': case 'B': return 11;
649 case 'c': case 'C': return 12;
650 case 'd': case 'D': return 13;
651 case 'e': case 'E': return 14;
652 case 'f': case 'F': return 15;
657 /* Split a line into arguments, where every argument can be in the
658 * following programming-language REPL-alike form:
660 * foo bar "newline are supported\n" and "\xff\x00otherstuff"
662 * The number of arguments is stored into *argc, and an array
663 * of sds is returned.
665 * The caller should free the resulting array of sds strings with
668 * Note that sdscatrepr() is able to convert back a string into
669 * a quoted string in the same format sdssplitargs() is able to parse.
671 * The function returns the allocated tokens on success, even when the
672 * input string is empty, or NULL if the input contains unbalanced
673 * quotes or closed quotes followed by non space characters
674 * as in: "foo"bar or "foo'
676 sds
*sdssplitargs(const char *line
, int *argc
) {
677 const char *p
= line
;
678 char *current
= NULL
;
679 char **vector
= NULL
;
684 while(*p
&& isspace((unsigned char)*p
)) p
++;
687 int inq
=0; /* set to 1 if we are in "quotes" */
688 int insq
=0; /* set to 1 if we are in 'single quotes' */
691 if (current
== NULL
) current
= sdsempty();
694 if (*p
== '\\' && *(p
+1) == 'x' &&
695 is_hex_digit(*(p
+2)) &&
696 is_hex_digit(*(p
+3)))
700 byte
= (unsigned char)((hex_digit_to_int(*(p
+2))*16)+
701 hex_digit_to_int(*(p
+3)));
702 current
= sdscatlen(current
,(char*)&byte
,1);
704 } else if (*p
== '\\' && *(p
+1)) {
709 case 'n': c
= '\n'; break;
710 case 'r': c
= '\r'; break;
711 case 't': c
= '\t'; break;
712 case 'b': c
= '\b'; break;
713 case 'a': c
= '\a'; break;
714 default: c
= *p
; break;
716 current
= sdscatlen(current
,&c
,1);
717 } else if (*p
== '"') {
718 /* closing quote must be followed by a space or
720 if (*(p
+1) && !isspace((unsigned char)*(p
+1))) goto err
;
723 /* unterminated quotes */
726 current
= sdscatlen(current
,p
,1);
729 if (*p
== '\\' && *(p
+1) == '\'') {
731 current
= sdscatlen(current
,"'",1);
732 } else if (*p
== '\'') {
733 /* closing quote must be followed by a space or
735 if (*(p
+1) && !isspace((unsigned char)*(p
+1))) goto err
;
738 /* unterminated quotes */
741 current
= sdscatlen(current
,p
,1);
759 current
= sdscatlen(current
,p
,1);
765 /* add the token to the vector */
766 vector
= (char**) realloc(vector
,(size_t)((*argc
)+1)*sizeof(char*));
767 vector
[*argc
] = current
;
771 /* Even on empty input string return something not NULL. */
772 if (vector
== NULL
) vector
= (char**) malloc(sizeof(void*));
779 sdsfree(vector
[*argc
]);
781 if (current
) sdsfree(current
);
786 /* Modify the string substituting all the occurrences of the set of
787 * characters specified in the 'from' string to the corresponding character
790 * For instance: sdsmapchars(mystring, "ho", "01", 2)
791 * will have the effect of turning the string "hello" into "0ell1".
793 * The function returns the sds string pointer, that is always the same
794 * as the input pointer since no resize is needed. */
795 sds
sdsmapchars(sds s
, const char *from
, const char *to
, size_t setlen
) {
796 size_t j
, i
, l
= sdslen(s
);
798 for (j
= 0; j
< l
; j
++) {
799 for (i
= 0; i
< setlen
; i
++) {
800 if (s
[j
] == from
[i
]) {
809 /* Join an array of C strings using the specified separator (also a C string).
810 * Returns the result as an sds string. */
811 sds
sdsjoin(char **argv
, int argc
, char *sep
, size_t seplen
) {
812 sds join
= sdsempty();
815 for (j
= 0; j
< argc
; j
++) {
816 join
= sdscat(join
, argv
[j
]);
817 if (j
!= argc
-1) join
= sdscatlen(join
,sep
,seplen
);
822 /* Like sdsjoin, but joins an array of SDS strings. */
823 sds
sdsjoinsds(sds
*argv
, int argc
, const char *sep
, size_t seplen
) {
824 sds join
= sdsempty();
827 for (j
= 0; j
< argc
; j
++) {
828 join
= sdscatsds(join
, argv
[j
]);
829 if (j
!= argc
-1) join
= sdscatlen(join
,sep
,seplen
);
836 #include "testhelp.h"
841 sds x
= sdsnew("foo"), y
;
843 test_cond("Create a string and obtain the length",
844 sdslen(x
) == 3 && memcmp(x
,"foo\0",4) == 0)
847 x
= sdsnewlen("foo",2);
848 test_cond("Create a string with specified length",
849 sdslen(x
) == 2 && memcmp(x
,"fo\0",3) == 0)
852 test_cond("Strings concatenation",
853 sdslen(x
) == 5 && memcmp(x
,"fobar\0",6) == 0);
856 test_cond("sdscpy() against an originally longer string",
857 sdslen(x
) == 1 && memcmp(x
,"a\0",2) == 0)
859 x
= sdscpy(x
,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk");
860 test_cond("sdscpy() against an originally shorter string",
862 memcmp(x
,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0)
865 x
= sdscatprintf(sdsempty(),"%d",123);
866 test_cond("sdscatprintf() seems working in the base case",
867 sdslen(x
) == 3 && memcmp(x
,"123\0",4) ==0)
870 x
= sdsnew("xxciaoyyy");
872 test_cond("sdstrim() correctly trims characters",
873 sdslen(x
) == 4 && memcmp(x
,"ciao\0",5) == 0)
877 test_cond("sdsrange(...,1,1)",
878 sdslen(y
) == 1 && memcmp(y
,"i\0",2) == 0)
883 test_cond("sdsrange(...,1,-1)",
884 sdslen(y
) == 3 && memcmp(y
,"iao\0",4) == 0)
889 test_cond("sdsrange(...,-2,-1)",
890 sdslen(y
) == 2 && memcmp(y
,"ao\0",3) == 0)
895 test_cond("sdsrange(...,2,1)",
896 sdslen(y
) == 0 && memcmp(y
,"\0",1) == 0)
901 test_cond("sdsrange(...,1,100)",
902 sdslen(y
) == 3 && memcmp(y
,"iao\0",4) == 0)
907 test_cond("sdsrange(...,100,100)",
908 sdslen(y
) == 0 && memcmp(y
,"\0",1) == 0)
914 test_cond("sdscmp(foo,foa)", sdscmp(x
,y
) > 0)
920 test_cond("sdscmp(bar,bar)", sdscmp(x
,y
) == 0)
926 test_cond("sdscmp(bar,bar)", sdscmp(x
,y
) < 0)
930 x
= sdsnewlen("\a\n\0foo\r",7);
931 y
= sdscatrepr(sdsempty(),x
,sdslen(x
));
932 test_cond("sdscatrepr(...data...)",
933 memcmp(y
,"\"\\a\\n\\x00foo\\r\"",15) == 0)
942 test_cond("sdsnew() free/len buffers", sh
->len
== 1 && sh
->free
== 0);
943 x
= sdsMakeRoomFor(x
,1);
945 test_cond("sdsMakeRoomFor()", sh
->len
== 1 && sh
->free
> 0);
949 test_cond("sdsIncrLen() -- content", x
[0] == '0' && x
[1] == '1');
950 test_cond("sdsIncrLen() -- len", sh
->len
== 2);
951 test_cond("sdsIncrLen() -- free", sh
->free
== oldfree
-1);
955 x
= sdsnew("0FoO1bar\n");
957 test_cond("sdstolower(...)",
958 memcmp(x
,"0foo1bar\n\0",10) == 0)
962 x
= sdsnew("0FoO1bar\n");
964 test_cond("sdstoupper(...)",
965 memcmp(x
,"0FOO1BAR\n\0",10) == 0)