PageRenderTime 74ms CodeModel.GetById 15ms app.highlight 49ms RepoModel.GetById 1ms app.codeStats 0ms

/hiredis/sds.c

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