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