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
sdsHdrSize(char type)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
sdsReqType(size_t string_size)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. */
sdsnewlen(const void * init,size_t initlen)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. */
sdsempty(void)149 sds sdsempty(void) {
150 return sdsnewlen("",0);
151 }
152
153 /* Create a new sds string starting from a null terminated C string. */
sdsnew(const char * init)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. */
sdsdup(const sds s)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. */
sdsfree(sds s)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. */
sdsupdatelen(sds s)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. */
sdsclear(sds s)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. */
sdsMakeRoomFor(sds s,size_t addlen)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. */
sdsRemoveFreeSpace(sds s)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 */
sdsAllocSize(sds s)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). */
sdsAllocPtr(sds s)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 */
sdsIncrLen(sds s,ssize_t incr)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. */
sdsgrowzero(sds s,size_t len)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. */
sdscatlen(sds s,const void * t,size_t len)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. */
sdscat(sds s,const char * t)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. */
sdscatsds(sds s,const sds t)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. */
sdscpylen(sds s,const char * t,size_t len)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(). */
sdscpy(sds s,const char * t)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
sdsll2str(char * s,long long value)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. */
sdsull2str(char * s,unsigned long long v)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 */
sdsfromlonglong(long long value)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. */
sdscatvprintf(sds s,const char * fmt,va_list ap)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 */
sdscatprintf(sds s,const char * fmt,...)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 */
sdscatfmt(sds s,char const * fmt,...)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 */
sdstrim(sds s,const char * cset)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 */
sdsrange(sds s,ssize_t start,ssize_t end)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'. */
sdstolower(sds 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'. */
sdstoupper(sds 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. */
sdscmp(const sds s1,const sds s2)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 */
sdssplitlen(const char * s,ssize_t len,const char * sep,int seplen,int * count)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. */
sdsfreesplitres(sds * tokens,int count)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. */
sdscatrepr(sds s,const char * p,size_t len)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. */
is_hex_digit(char c)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 */
hex_digit_to_int(char c)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 */
sdssplitargs(const char * line,int * argc)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. */
sdsmapchars(sds s,const char * from,const char * to,size_t setlen)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. */
sdsjoin(char ** argv,int argc,char * sep)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. */
sdsjoinsds(sds * argv,int argc,const char * sep,size_t seplen)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. */
sds_malloc(size_t size)1118 void *sds_malloc(size_t size) { return s_malloc(size); }
sds_realloc(void * ptr,size_t size)1119 void *sds_realloc(void *ptr, size_t size) { return s_realloc(ptr,size); }
sds_free(void * ptr)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)
sdsTest(void)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
main(void)1293 int main(void) {
1294 return sdsTest();
1295 }
1296 #endif
1297