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