durable_rules 0.33.13 → 0.34.01

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,116 @@
1
+ /*
2
+ * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
3
+ * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
4
+ *
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions are met:
9
+ *
10
+ * * Redistributions of source code must retain the above copyright notice,
11
+ * this list of conditions and the following disclaimer.
12
+ * * Redistributions in binary form must reproduce the above copyright
13
+ * notice, this list of conditions and the following disclaimer in the
14
+ * documentation and/or other materials provided with the distribution.
15
+ * * Neither the name of Redis nor the names of its contributors may be used
16
+ * to endorse or promote products derived from this software without
17
+ * specific prior written permission.
18
+ *
19
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
+ * POSSIBILITY OF SUCH DAMAGE.
30
+ */
31
+
32
+
33
+ #ifndef __HIREDIS_READ_H
34
+ #define __HIREDIS_READ_H
35
+ #include <stdio.h> /* for size_t */
36
+
37
+ #define REDIS_ERR -1
38
+ #define REDIS_OK 0
39
+
40
+ /* When an error occurs, the err flag in a context is set to hold the type of
41
+ * error that occured. REDIS_ERR_IO means there was an I/O error and you
42
+ * should use the "errno" variable to find out what is wrong.
43
+ * For other values, the "errstr" field will hold a description. */
44
+ #define REDIS_ERR_IO 1 /* Error in read or write */
45
+ #define REDIS_ERR_EOF 3 /* End of file */
46
+ #define REDIS_ERR_PROTOCOL 4 /* Protocol error */
47
+ #define REDIS_ERR_OOM 5 /* Out of memory */
48
+ #define REDIS_ERR_OTHER 2 /* Everything else... */
49
+
50
+ #define REDIS_REPLY_STRING 1
51
+ #define REDIS_REPLY_ARRAY 2
52
+ #define REDIS_REPLY_INTEGER 3
53
+ #define REDIS_REPLY_NIL 4
54
+ #define REDIS_REPLY_STATUS 5
55
+ #define REDIS_REPLY_ERROR 6
56
+
57
+ #define REDIS_READER_MAX_BUF (1024*16) /* Default max unused reader buffer. */
58
+
59
+ #ifdef __cplusplus
60
+ extern "C" {
61
+ #endif
62
+
63
+ typedef struct redisReadTask {
64
+ int type;
65
+ int elements; /* number of elements in multibulk container */
66
+ int idx; /* index in parent (array) object */
67
+ void *obj; /* holds user-generated value for a read task */
68
+ struct redisReadTask *parent; /* parent task */
69
+ void *privdata; /* user-settable arbitrary field */
70
+ } redisReadTask;
71
+
72
+ typedef struct redisReplyObjectFunctions {
73
+ void *(*createString)(const redisReadTask*, char*, size_t);
74
+ void *(*createArray)(const redisReadTask*, int);
75
+ void *(*createInteger)(const redisReadTask*, long long);
76
+ void *(*createNil)(const redisReadTask*);
77
+ void (*freeObject)(void*);
78
+ } redisReplyObjectFunctions;
79
+
80
+ typedef struct redisReader {
81
+ int err; /* Error flags, 0 when there is no error */
82
+ char errstr[128]; /* String representation of error when applicable */
83
+
84
+ char *buf; /* Read buffer */
85
+ size_t pos; /* Buffer cursor */
86
+ size_t len; /* Buffer length */
87
+ size_t maxbuf; /* Max length of unused buffer */
88
+
89
+ redisReadTask rstack[9];
90
+ int ridx; /* Index of current read task */
91
+ void *reply; /* Temporary reply pointer */
92
+
93
+ redisReplyObjectFunctions *fn;
94
+ void *privdata;
95
+ } redisReader;
96
+
97
+ /* Public API for the protocol parser. */
98
+ redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn);
99
+ void redisReaderFree(redisReader *r);
100
+ int redisReaderFeed(redisReader *r, const char *buf, size_t len);
101
+ int redisReaderGetReply(redisReader *r, void **reply);
102
+
103
+ /* Backwards compatibility, can be removed on big version bump. */
104
+ #define redisReplyReaderCreate redisReaderCreate
105
+ #define redisReplyReaderFree redisReaderFree
106
+ #define redisReplyReaderFeed redisReaderFeed
107
+ #define redisReplyReaderGetReply redisReaderGetReply
108
+ #define redisReplyReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p))
109
+ #define redisReplyReaderGetObject(_r) (((redisReader*)(_r))->reply)
110
+ #define redisReplyReaderGetError(_r) (((redisReader*)(_r))->errstr)
111
+
112
+ #ifdef __cplusplus
113
+ }
114
+ #endif
115
+
116
+ #endif
data/deps/hiredis/sds.c CHANGED
@@ -1,6 +1,6 @@
1
- /* SDSLib, A C dynamic strings library
1
+ /* SDS (Simple Dynamic Strings), A C dynamic strings library.
2
2
  *
3
- * Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
3
+ * Copyright (c) 2006-2014, Salvatore Sanfilippo <antirez at gmail dot com>
4
4
  * All rights reserved.
5
5
  *
6
6
  * Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,8 @@
33
33
  #include <string.h>
34
34
  #include <ctype.h>
35
35
  #include <assert.h>
36
+
36
37
  #include "sds.h"
37
- #include "zmalloc.h"
38
38
 
39
39
  /* Create a new sds string with the content specified by the 'init' pointer
40
40
  * and 'initlen'.
@@ -52,9 +52,9 @@ sds sdsnewlen(const void *init, size_t initlen) {
52
52
  struct sdshdr *sh;
53
53
 
54
54
  if (init) {
55
- sh = zmalloc(sizeof(struct sdshdr)+initlen+1);
55
+ sh = malloc(sizeof *sh+initlen+1);
56
56
  } else {
57
- sh = zcalloc(sizeof(struct sdshdr)+initlen+1);
57
+ sh = calloc(sizeof *sh+initlen+1,1);
58
58
  }
59
59
  if (sh == NULL) return NULL;
60
60
  sh->len = initlen;
@@ -85,7 +85,7 @@ sds sdsdup(const sds s) {
85
85
  /* Free an sds string. No operation is performed if 's' is NULL. */
86
86
  void sdsfree(sds s) {
87
87
  if (s == NULL) return;
88
- zfree(s-sizeof(struct sdshdr));
88
+ free(s-sizeof(struct sdshdr));
89
89
  }
90
90
 
91
91
  /* Set the sds string length to the length as obtained with strlen(), so
@@ -103,7 +103,7 @@ void sdsfree(sds s) {
103
103
  * the output will be "6" as the string was modified but the logical length
104
104
  * remains 6 bytes. */
105
105
  void sdsupdatelen(sds s) {
106
- struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
106
+ struct sdshdr *sh = (void*) (s-sizeof *sh);
107
107
  int reallen = strlen(s);
108
108
  sh->free += (sh->len-reallen);
109
109
  sh->len = reallen;
@@ -114,7 +114,7 @@ void sdsupdatelen(sds s) {
114
114
  * so that next append operations will not require allocations up to the
115
115
  * number of bytes previously available. */
116
116
  void sdsclear(sds s) {
117
- struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
117
+ struct sdshdr *sh = (void*) (s-sizeof *sh);
118
118
  sh->free += sh->len;
119
119
  sh->len = 0;
120
120
  sh->buf[0] = '\0';
@@ -123,7 +123,7 @@ void sdsclear(sds s) {
123
123
  /* Enlarge the free space at the end of the sds string so that the caller
124
124
  * is sure that after calling this function can overwrite up to addlen
125
125
  * bytes after the end of the string, plus one more byte for nul term.
126
- *
126
+ *
127
127
  * Note: this does not change the *length* of the sds string as returned
128
128
  * by sdslen(), but only the free buffer space we have. */
129
129
  sds sdsMakeRoomFor(sds s, size_t addlen) {
@@ -133,13 +133,13 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
133
133
 
134
134
  if (free >= addlen) return s;
135
135
  len = sdslen(s);
136
- sh = (void*) (s-(sizeof(struct sdshdr)));
136
+ sh = (void*) (s-sizeof *sh);
137
137
  newlen = (len+addlen);
138
138
  if (newlen < SDS_MAX_PREALLOC)
139
139
  newlen *= 2;
140
140
  else
141
141
  newlen += SDS_MAX_PREALLOC;
142
- newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1);
142
+ newsh = realloc(sh, sizeof *newsh+newlen+1);
143
143
  if (newsh == NULL) return NULL;
144
144
 
145
145
  newsh->free = newlen - len;
@@ -155,8 +155,8 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
155
155
  sds sdsRemoveFreeSpace(sds s) {
156
156
  struct sdshdr *sh;
157
157
 
158
- sh = (void*) (s-(sizeof(struct sdshdr)));
159
- sh = zrealloc(sh, sizeof(struct sdshdr)+sh->len+1);
158
+ sh = (void*) (s-sizeof *sh);
159
+ sh = realloc(sh, sizeof *sh+sh->len+1);
160
160
  sh->free = 0;
161
161
  return sh->buf;
162
162
  }
@@ -169,7 +169,7 @@ sds sdsRemoveFreeSpace(sds s) {
169
169
  * 4) The implicit null term.
170
170
  */
171
171
  size_t sdsAllocSize(sds s) {
172
- struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
172
+ struct sdshdr *sh = (void*) (s-sizeof *sh);
173
173
 
174
174
  return sizeof(*sh)+sh->len+sh->free+1;
175
175
  }
@@ -198,7 +198,7 @@ size_t sdsAllocSize(sds s) {
198
198
  * sdsIncrLen(s, nread);
199
199
  */
200
200
  void sdsIncrLen(sds s, int incr) {
201
- struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
201
+ struct sdshdr *sh = (void*) (s-sizeof *sh);
202
202
 
203
203
  assert(sh->free >= incr);
204
204
  sh->len += incr;
@@ -213,7 +213,7 @@ void sdsIncrLen(sds s, int incr) {
213
213
  * if the specified length is smaller than the current length, no operation
214
214
  * is performed. */
215
215
  sds sdsgrowzero(sds s, size_t len) {
216
- struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
216
+ struct sdshdr *sh = (void*) (s-sizeof *sh);
217
217
  size_t totlen, curlen = sh->len;
218
218
 
219
219
  if (len <= curlen) return s;
@@ -221,7 +221,7 @@ sds sdsgrowzero(sds s, size_t len) {
221
221
  if (s == NULL) return NULL;
222
222
 
223
223
  /* Make sure added region doesn't contain garbage */
224
- sh = (void*)(s-(sizeof(struct sdshdr)));
224
+ sh = (void*)(s-sizeof *sh);
225
225
  memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */
226
226
  totlen = sh->len+sh->free;
227
227
  sh->len = len;
@@ -240,7 +240,7 @@ sds sdscatlen(sds s, const void *t, size_t len) {
240
240
 
241
241
  s = sdsMakeRoomFor(s,len);
242
242
  if (s == NULL) return NULL;
243
- sh = (void*) (s-(sizeof(struct sdshdr)));
243
+ sh = (void*) (s-sizeof *sh);
244
244
  memcpy(s+curlen, t, len);
245
245
  sh->len = curlen+len;
246
246
  sh->free = sh->free-len;
@@ -267,13 +267,13 @@ sds sdscatsds(sds s, const sds t) {
267
267
  /* Destructively modify the sds string 's' to hold the specified binary
268
268
  * safe string pointed by 't' of length 'len' bytes. */
269
269
  sds sdscpylen(sds s, const char *t, size_t len) {
270
- struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
270
+ struct sdshdr *sh = (void*) (s-sizeof *sh);
271
271
  size_t totlen = sh->free+sh->len;
272
272
 
273
273
  if (totlen < len) {
274
274
  s = sdsMakeRoomFor(s,len-sh->len);
275
275
  if (s == NULL) return NULL;
276
- sh = (void*) (s-(sizeof(struct sdshdr)));
276
+ sh = (void*) (s-sizeof *sh);
277
277
  totlen = sh->free+sh->len;
278
278
  }
279
279
  memcpy(s, t, len);
@@ -289,6 +289,73 @@ sds sdscpy(sds s, const char *t) {
289
289
  return sdscpylen(s, t, strlen(t));
290
290
  }
291
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
299
+ int 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. */
331
+ int 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
+
292
359
  /* Like sdscatpritf() but gets va_list instead of being variadic. */
293
360
  sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
294
361
  va_list cpy;
@@ -296,20 +363,20 @@ sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
296
363
  size_t buflen = 16;
297
364
 
298
365
  while(1) {
299
- buf = zmalloc(buflen);
366
+ buf = malloc(buflen);
300
367
  if (buf == NULL) return NULL;
301
368
  buf[buflen-2] = '\0';
302
369
  va_copy(cpy,ap);
303
370
  vsnprintf(buf, buflen, fmt, cpy);
304
371
  if (buf[buflen-2] != '\0') {
305
- zfree(buf);
372
+ free(buf);
306
373
  buflen *= 2;
307
374
  continue;
308
375
  }
309
376
  break;
310
377
  }
311
378
  t = sdscat(s, buf);
312
- zfree(buf);
379
+ free(buf);
313
380
  return t;
314
381
  }
315
382
 
@@ -321,8 +388,8 @@ sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
321
388
  *
322
389
  * Example:
323
390
  *
324
- * s = sdsempty("Sum is: ");
325
- * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b).
391
+ * s = sdsnew("Sum is: ");
392
+ * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b);
326
393
  *
327
394
  * Often you need to create a string from scratch with the printf-alike
328
395
  * format. When this is the need, just use sdsempty() as the target string:
@@ -338,6 +405,127 @@ sds sdscatprintf(sds s, const char *fmt, ...) {
338
405
  return t;
339
406
  }
340
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
+ */
425
+ sds 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
+
341
529
  /* Remove the part of the string from left and from right composed just of
342
530
  * contiguous characters found in 'cset', that is a null terminted C string.
343
531
  *
@@ -352,8 +540,8 @@ sds sdscatprintf(sds s, const char *fmt, ...) {
352
540
  *
353
541
  * Output will be just "Hello World".
354
542
  */
355
- sds sdstrim(sds s, const char *cset) {
356
- struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
543
+ void sdstrim(sds s, const char *cset) {
544
+ struct sdshdr *sh = (void*) (s-sizeof *sh);
357
545
  char *start, *end, *sp, *ep;
358
546
  size_t len;
359
547
 
@@ -366,7 +554,6 @@ sds sdstrim(sds s, const char *cset) {
366
554
  sh->buf[len] = '\0';
367
555
  sh->free = sh->free+(sh->len-len);
368
556
  sh->len = len;
369
- return s;
370
557
  }
371
558
 
372
559
  /* Turn the string into a smaller (or equal) string containing only the
@@ -383,10 +570,10 @@ sds sdstrim(sds s, const char *cset) {
383
570
  * Example:
384
571
  *
385
572
  * s = sdsnew("Hello World");
386
- * sdstrim(s,1,-1); => "ello Worl"
573
+ * sdsrange(s,1,-1); => "ello World"
387
574
  */
388
575
  void sdsrange(sds s, int start, int end) {
389
- struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
576
+ struct sdshdr *sh = (void*) (s-sizeof *sh);
390
577
  size_t newlen, len = sdslen(s);
391
578
 
392
579
  if (len == 0) return;
@@ -474,7 +661,7 @@ sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count
474
661
 
475
662
  if (seplen < 1 || len < 0) return NULL;
476
663
 
477
- tokens = zmalloc(sizeof(sds)*slots);
664
+ tokens = malloc(sizeof(sds)*slots);
478
665
  if (tokens == NULL) return NULL;
479
666
 
480
667
  if (len == 0) {
@@ -487,7 +674,7 @@ sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count
487
674
  sds *newtokens;
488
675
 
489
676
  slots *= 2;
490
- newtokens = zrealloc(tokens,sizeof(sds)*slots);
677
+ newtokens = realloc(tokens,sizeof(sds)*slots);
491
678
  if (newtokens == NULL) goto cleanup;
492
679
  tokens = newtokens;
493
680
  }
@@ -511,7 +698,7 @@ cleanup:
511
698
  {
512
699
  int i;
513
700
  for (i = 0; i < elements; i++) sdsfree(tokens[i]);
514
- zfree(tokens);
701
+ free(tokens);
515
702
  *count = 0;
516
703
  return NULL;
517
704
  }
@@ -522,7 +709,7 @@ void sdsfreesplitres(sds *tokens, int count) {
522
709
  if (!tokens) return;
523
710
  while(count--)
524
711
  sdsfree(tokens[count]);
525
- zfree(tokens);
712
+ free(tokens);
526
713
  }
527
714
 
528
715
  /* Create an sds string from a long long value. It is much faster than:
@@ -582,7 +769,7 @@ int is_hex_digit(char c) {
582
769
  (c >= 'A' && c <= 'F');
583
770
  }
584
771
 
585
- /* Helper function for sdssplitargs() that converts an hex digit into an
772
+ /* Helper function for sdssplitargs() that converts a hex digit into an
586
773
  * integer from 0 to 15 */
587
774
  int hex_digit_to_int(char c) {
588
775
  switch(c) {
@@ -715,13 +902,13 @@ sds *sdssplitargs(const char *line, int *argc) {
715
902
  if (*p) p++;
716
903
  }
717
904
  /* add the token to the vector */
718
- vector = zrealloc(vector,((*argc)+1)*sizeof(char*));
905
+ vector = realloc(vector,((*argc)+1)*sizeof(char*));
719
906
  vector[*argc] = current;
720
907
  (*argc)++;
721
908
  current = NULL;
722
909
  } else {
723
910
  /* Even on empty input string return something not NULL. */
724
- if (vector == NULL) vector = zmalloc(sizeof(void*));
911
+ if (vector == NULL) vector = malloc(sizeof(void*));
725
912
  return vector;
726
913
  }
727
914
  }
@@ -729,7 +916,7 @@ sds *sdssplitargs(const char *line, int *argc) {
729
916
  err:
730
917
  while((*argc)--)
731
918
  sdsfree(vector[*argc]);
732
- zfree(vector);
919
+ free(vector);
733
920
  if (current) sdsfree(current);
734
921
  *argc = 0;
735
922
  return NULL;
@@ -760,13 +947,25 @@ sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
760
947
 
761
948
  /* Join an array of C strings using the specified separator (also a C string).
762
949
  * Returns the result as an sds string. */
763
- sds sdsjoin(char **argv, int argc, char *sep) {
950
+ sds sdsjoin(char **argv, int argc, char *sep, size_t seplen) {
764
951
  sds join = sdsempty();
765
952
  int j;
766
953
 
767
954
  for (j = 0; j < argc; j++) {
768
955
  join = sdscat(join, argv[j]);
769
- if (j != argc-1) join = sdscat(join,sep);
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. */
962
+ sds 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);
770
969
  }
771
970
  return join;
772
971
  }
@@ -807,36 +1006,43 @@ int main(void) {
807
1006
  sdslen(x) == 3 && memcmp(x,"123\0",4) ==0)
808
1007
 
809
1008
  sdsfree(x);
810
- x = sdstrim(sdsnew("xxciaoyyy"),"xy");
1009
+ x = sdsnew("xxciaoyyy");
1010
+ sdstrim(x,"xy");
811
1011
  test_cond("sdstrim() correctly trims characters",
812
1012
  sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0)
813
1013
 
814
- y = sdsrange(sdsdup(x),1,1);
1014
+ y = sdsdup(x);
1015
+ sdsrange(y,1,1);
815
1016
  test_cond("sdsrange(...,1,1)",
816
1017
  sdslen(y) == 1 && memcmp(y,"i\0",2) == 0)
817
1018
 
818
1019
  sdsfree(y);
819
- y = sdsrange(sdsdup(x),1,-1);
1020
+ y = sdsdup(x);
1021
+ sdsrange(y,1,-1);
820
1022
  test_cond("sdsrange(...,1,-1)",
821
1023
  sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
822
1024
 
823
1025
  sdsfree(y);
824
- y = sdsrange(sdsdup(x),-2,-1);
1026
+ y = sdsdup(x);
1027
+ sdsrange(y,-2,-1);
825
1028
  test_cond("sdsrange(...,-2,-1)",
826
1029
  sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0)
827
1030
 
828
1031
  sdsfree(y);
829
- y = sdsrange(sdsdup(x),2,1);
1032
+ y = sdsdup(x);
1033
+ sdsrange(y,2,1);
830
1034
  test_cond("sdsrange(...,2,1)",
831
1035
  sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
832
1036
 
833
1037
  sdsfree(y);
834
- y = sdsrange(sdsdup(x),1,100);
1038
+ y = sdsdup(x);
1039
+ sdsrange(y,1,100);
835
1040
  test_cond("sdsrange(...,1,100)",
836
1041
  sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
837
1042
 
838
1043
  sdsfree(y);
839
- y = sdsrange(sdsdup(x),100,100);
1044
+ y = sdsdup(x);
1045
+ sdsrange(y,100,100);
840
1046
  test_cond("sdsrange(...,100,100)",
841
1047
  sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
842
1048
 
@@ -858,6 +1064,13 @@ int main(void) {
858
1064
  y = sdsnew("bar");
859
1065
  test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0)
860
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
+
861
1074
  {
862
1075
  int oldfree;
863
1076