hiredis 0.6.1 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/ext/hiredis_ext/connection.c +4 -3
- data/ext/hiredis_ext/reader.c +12 -6
- data/lib/hiredis/version.rb +1 -1
- data/vendor/hiredis/Makefile +53 -34
- data/vendor/hiredis/async.c +40 -9
- data/vendor/hiredis/async.h +1 -0
- data/vendor/hiredis/dict.c +2 -2
- data/vendor/hiredis/fmacros.h +4 -13
- data/vendor/hiredis/hiredis.c +50 -23
- data/vendor/hiredis/hiredis.h +37 -27
- data/vendor/hiredis/net.c +99 -22
- data/vendor/hiredis/net.h +4 -6
- data/vendor/hiredis/read.c +119 -44
- data/vendor/hiredis/read.h +4 -9
- data/vendor/hiredis/sds.c +342 -165
- data/vendor/hiredis/sds.h +184 -13
- data/vendor/hiredis/sdsalloc.h +42 -0
- data/vendor/hiredis/test.c +187 -14
- data/vendor/hiredis/win32.h +42 -0
- metadata +5 -3
data/vendor/hiredis/net.h
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
/* Extracted from anet.c to work properly with Hiredis error reporting.
|
2
2
|
*
|
3
|
-
* Copyright (c)
|
4
|
-
* Copyright (c) 2010-
|
3
|
+
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
4
|
+
* Copyright (c) 2010-2014, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
5
|
+
* Copyright (c) 2015, Matt Stancliff <matt at genges dot com>,
|
6
|
+
* Jan-Erik Rediger <janerik at fnordig dot com>
|
5
7
|
*
|
6
8
|
* All rights reserved.
|
7
9
|
*
|
@@ -35,10 +37,6 @@
|
|
35
37
|
|
36
38
|
#include "hiredis.h"
|
37
39
|
|
38
|
-
#if defined(__sun)
|
39
|
-
#define AF_LOCAL AF_UNIX
|
40
|
-
#endif
|
41
|
-
|
42
40
|
int redisCheckSocketError(redisContext *c);
|
43
41
|
int redisContextSetTimeout(redisContext *c, const struct timeval tv);
|
44
42
|
int redisContextConnectTcp(redisContext *c, const char *addr, int port, const struct timeval *timeout);
|
data/vendor/hiredis/read.c
CHANGED
@@ -33,10 +33,13 @@
|
|
33
33
|
#include "fmacros.h"
|
34
34
|
#include <string.h>
|
35
35
|
#include <stdlib.h>
|
36
|
+
#ifndef _MSC_VER
|
36
37
|
#include <unistd.h>
|
38
|
+
#endif
|
37
39
|
#include <assert.h>
|
38
40
|
#include <errno.h>
|
39
41
|
#include <ctype.h>
|
42
|
+
#include <limits.h>
|
40
43
|
|
41
44
|
#include "read.h"
|
42
45
|
#include "sds.h"
|
@@ -50,11 +53,9 @@ static void __redisReaderSetError(redisReader *r, int type, const char *str) {
|
|
50
53
|
}
|
51
54
|
|
52
55
|
/* Clear input buffer on errors. */
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
r->pos = r->len = 0;
|
57
|
-
}
|
56
|
+
sdsfree(r->buf);
|
57
|
+
r->buf = NULL;
|
58
|
+
r->pos = r->len = 0;
|
58
59
|
|
59
60
|
/* Reset task stack. */
|
60
61
|
r->ridx = -1;
|
@@ -125,7 +126,7 @@ static char *seekNewline(char *s, size_t len) {
|
|
125
126
|
* might not have a trailing NULL character. */
|
126
127
|
while (pos < _len) {
|
127
128
|
while(pos < _len && s[pos] != '\r') pos++;
|
128
|
-
if (
|
129
|
+
if (pos==_len) {
|
129
130
|
/* Not found. */
|
130
131
|
return NULL;
|
131
132
|
} else {
|
@@ -141,33 +142,79 @@ static char *seekNewline(char *s, size_t len) {
|
|
141
142
|
return NULL;
|
142
143
|
}
|
143
144
|
|
144
|
-
/*
|
145
|
-
*
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
145
|
+
/* Convert a string into a long long. Returns REDIS_OK if the string could be
|
146
|
+
* parsed into a (non-overflowing) long long, REDIS_ERR otherwise. The value
|
147
|
+
* will be set to the parsed value when appropriate.
|
148
|
+
*
|
149
|
+
* Note that this function demands that the string strictly represents
|
150
|
+
* a long long: no spaces or other characters before or after the string
|
151
|
+
* representing the number are accepted, nor zeroes at the start if not
|
152
|
+
* for the string "0" representing the zero number.
|
153
|
+
*
|
154
|
+
* Because of its strictness, it is safe to use this function to check if
|
155
|
+
* you can convert a string into a long long, and obtain back the string
|
156
|
+
* from the number without any loss in the string representation. */
|
157
|
+
static int string2ll(const char *s, size_t slen, long long *value) {
|
158
|
+
const char *p = s;
|
159
|
+
size_t plen = 0;
|
160
|
+
int negative = 0;
|
161
|
+
unsigned long long v;
|
162
|
+
|
163
|
+
if (plen == slen)
|
164
|
+
return REDIS_ERR;
|
165
|
+
|
166
|
+
/* Special case: first and only digit is 0. */
|
167
|
+
if (slen == 1 && p[0] == '0') {
|
168
|
+
if (value != NULL) *value = 0;
|
169
|
+
return REDIS_OK;
|
157
170
|
}
|
158
171
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
172
|
+
if (p[0] == '-') {
|
173
|
+
negative = 1;
|
174
|
+
p++; plen++;
|
175
|
+
|
176
|
+
/* Abort on only a negative sign. */
|
177
|
+
if (plen == slen)
|
178
|
+
return REDIS_ERR;
|
179
|
+
}
|
180
|
+
|
181
|
+
/* First digit should be 1-9, otherwise the string should just be 0. */
|
182
|
+
if (p[0] >= '1' && p[0] <= '9') {
|
183
|
+
v = p[0]-'0';
|
184
|
+
p++; plen++;
|
185
|
+
} else if (p[0] == '0' && slen == 1) {
|
186
|
+
*value = 0;
|
187
|
+
return REDIS_OK;
|
188
|
+
} else {
|
189
|
+
return REDIS_ERR;
|
168
190
|
}
|
169
191
|
|
170
|
-
|
192
|
+
while (plen < slen && p[0] >= '0' && p[0] <= '9') {
|
193
|
+
if (v > (ULLONG_MAX / 10)) /* Overflow. */
|
194
|
+
return REDIS_ERR;
|
195
|
+
v *= 10;
|
196
|
+
|
197
|
+
if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */
|
198
|
+
return REDIS_ERR;
|
199
|
+
v += p[0]-'0';
|
200
|
+
|
201
|
+
p++; plen++;
|
202
|
+
}
|
203
|
+
|
204
|
+
/* Return if not all bytes were used. */
|
205
|
+
if (plen < slen)
|
206
|
+
return REDIS_ERR;
|
207
|
+
|
208
|
+
if (negative) {
|
209
|
+
if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */
|
210
|
+
return REDIS_ERR;
|
211
|
+
if (value != NULL) *value = -v;
|
212
|
+
} else {
|
213
|
+
if (v > LLONG_MAX) /* Overflow. */
|
214
|
+
return REDIS_ERR;
|
215
|
+
if (value != NULL) *value = v;
|
216
|
+
}
|
217
|
+
return REDIS_OK;
|
171
218
|
}
|
172
219
|
|
173
220
|
static char *readLine(redisReader *r, int *_len) {
|
@@ -218,10 +265,17 @@ static int processLineItem(redisReader *r) {
|
|
218
265
|
|
219
266
|
if ((p = readLine(r,&len)) != NULL) {
|
220
267
|
if (cur->type == REDIS_REPLY_INTEGER) {
|
221
|
-
if (r->fn && r->fn->createInteger)
|
222
|
-
|
223
|
-
|
268
|
+
if (r->fn && r->fn->createInteger) {
|
269
|
+
long long v;
|
270
|
+
if (string2ll(p, len, &v) == REDIS_ERR) {
|
271
|
+
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
272
|
+
"Bad integer value");
|
273
|
+
return REDIS_ERR;
|
274
|
+
}
|
275
|
+
obj = r->fn->createInteger(cur,v);
|
276
|
+
} else {
|
224
277
|
obj = (void*)REDIS_REPLY_INTEGER;
|
278
|
+
}
|
225
279
|
} else {
|
226
280
|
/* Type will be error or status. */
|
227
281
|
if (r->fn && r->fn->createString)
|
@@ -248,7 +302,7 @@ static int processBulkItem(redisReader *r) {
|
|
248
302
|
redisReadTask *cur = &(r->rstack[r->ridx]);
|
249
303
|
void *obj = NULL;
|
250
304
|
char *p, *s;
|
251
|
-
long len;
|
305
|
+
long long len;
|
252
306
|
unsigned long bytelen;
|
253
307
|
int success = 0;
|
254
308
|
|
@@ -257,9 +311,20 @@ static int processBulkItem(redisReader *r) {
|
|
257
311
|
if (s != NULL) {
|
258
312
|
p = r->buf+r->pos;
|
259
313
|
bytelen = s-(r->buf+r->pos)+2; /* include \r\n */
|
260
|
-
len = readLongLong(p);
|
261
314
|
|
262
|
-
if (len
|
315
|
+
if (string2ll(p, bytelen - 2, &len) == REDIS_ERR) {
|
316
|
+
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
317
|
+
"Bad bulk string length");
|
318
|
+
return REDIS_ERR;
|
319
|
+
}
|
320
|
+
|
321
|
+
if (len < -1 || (LLONG_MAX > SIZE_MAX && len > (long long)SIZE_MAX)) {
|
322
|
+
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
323
|
+
"Bulk string length out of range");
|
324
|
+
return REDIS_ERR;
|
325
|
+
}
|
326
|
+
|
327
|
+
if (len == -1) {
|
263
328
|
/* The nil object can always be created. */
|
264
329
|
if (r->fn && r->fn->createNil)
|
265
330
|
obj = r->fn->createNil(cur);
|
@@ -301,8 +366,8 @@ static int processMultiBulkItem(redisReader *r) {
|
|
301
366
|
redisReadTask *cur = &(r->rstack[r->ridx]);
|
302
367
|
void *obj;
|
303
368
|
char *p;
|
304
|
-
long elements;
|
305
|
-
int root = 0;
|
369
|
+
long long elements;
|
370
|
+
int root = 0, len;
|
306
371
|
|
307
372
|
/* Set error for nested multi bulks with depth > 7 */
|
308
373
|
if (r->ridx == 8) {
|
@@ -311,10 +376,21 @@ static int processMultiBulkItem(redisReader *r) {
|
|
311
376
|
return REDIS_ERR;
|
312
377
|
}
|
313
378
|
|
314
|
-
if ((p = readLine(r
|
315
|
-
|
379
|
+
if ((p = readLine(r,&len)) != NULL) {
|
380
|
+
if (string2ll(p, len, &elements) == REDIS_ERR) {
|
381
|
+
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
382
|
+
"Bad multi-bulk length");
|
383
|
+
return REDIS_ERR;
|
384
|
+
}
|
385
|
+
|
316
386
|
root = (r->ridx == 0);
|
317
387
|
|
388
|
+
if (elements < -1 || elements > INT_MAX) {
|
389
|
+
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
|
390
|
+
"Multi-bulk length out of range");
|
391
|
+
return REDIS_ERR;
|
392
|
+
}
|
393
|
+
|
318
394
|
if (elements == -1) {
|
319
395
|
if (r->fn && r->fn->createNil)
|
320
396
|
obj = r->fn->createNil(cur);
|
@@ -414,12 +490,10 @@ static int processItem(redisReader *r) {
|
|
414
490
|
redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) {
|
415
491
|
redisReader *r;
|
416
492
|
|
417
|
-
r = calloc(sizeof(redisReader)
|
493
|
+
r = calloc(1,sizeof(redisReader));
|
418
494
|
if (r == NULL)
|
419
495
|
return NULL;
|
420
496
|
|
421
|
-
r->err = 0;
|
422
|
-
r->errstr[0] = '\0';
|
423
497
|
r->fn = fn;
|
424
498
|
r->buf = sdsempty();
|
425
499
|
r->maxbuf = REDIS_READER_MAX_BUF;
|
@@ -433,10 +507,11 @@ redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) {
|
|
433
507
|
}
|
434
508
|
|
435
509
|
void redisReaderFree(redisReader *r) {
|
510
|
+
if (r == NULL)
|
511
|
+
return;
|
436
512
|
if (r->reply != NULL && r->fn && r->fn->freeObject)
|
437
513
|
r->fn->freeObject(r->reply);
|
438
|
-
|
439
|
-
sdsfree(r->buf);
|
514
|
+
sdsfree(r->buf);
|
440
515
|
free(r);
|
441
516
|
}
|
442
517
|
|
data/vendor/hiredis/read.h
CHANGED
@@ -38,7 +38,7 @@
|
|
38
38
|
#define REDIS_OK 0
|
39
39
|
|
40
40
|
/* When an error occurs, the err flag in a context is set to hold the type of
|
41
|
-
* error that
|
41
|
+
* error that occurred. REDIS_ERR_IO means there was an I/O error and you
|
42
42
|
* should use the "errno" variable to find out what is wrong.
|
43
43
|
* For other values, the "errstr" field will hold a description. */
|
44
44
|
#define REDIS_ERR_IO 1 /* Error in read or write */
|
@@ -100,14 +100,9 @@ void redisReaderFree(redisReader *r);
|
|
100
100
|
int redisReaderFeed(redisReader *r, const char *buf, size_t len);
|
101
101
|
int redisReaderGetReply(redisReader *r, void **reply);
|
102
102
|
|
103
|
-
|
104
|
-
#define
|
105
|
-
#define
|
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)
|
103
|
+
#define redisReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p))
|
104
|
+
#define redisReaderGetObject(_r) (((redisReader*)(_r))->reply)
|
105
|
+
#define redisReaderGetError(_r) (((redisReader*)(_r))->errstr)
|
111
106
|
|
112
107
|
#ifdef __cplusplus
|
113
108
|
}
|
data/vendor/hiredis/sds.c
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
/*
|
1
|
+
/* SDSLib 2.0 -- A C dynamic strings library
|
2
2
|
*
|
3
|
-
* Copyright (c) 2006-
|
3
|
+
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
4
|
+
* Copyright (c) 2015, Oran Agra
|
5
|
+
* Copyright (c) 2015, Redis Labs, Inc
|
4
6
|
* All rights reserved.
|
5
7
|
*
|
6
8
|
* Redistribution and use in source and binary forms, with or without
|
@@ -33,8 +35,36 @@
|
|
33
35
|
#include <string.h>
|
34
36
|
#include <ctype.h>
|
35
37
|
#include <assert.h>
|
36
|
-
|
37
38
|
#include "sds.h"
|
39
|
+
#include "sdsalloc.h"
|
40
|
+
|
41
|
+
static inline int sdsHdrSize(char type) {
|
42
|
+
switch(type&SDS_TYPE_MASK) {
|
43
|
+
case SDS_TYPE_5:
|
44
|
+
return sizeof(struct sdshdr5);
|
45
|
+
case SDS_TYPE_8:
|
46
|
+
return sizeof(struct sdshdr8);
|
47
|
+
case SDS_TYPE_16:
|
48
|
+
return sizeof(struct sdshdr16);
|
49
|
+
case SDS_TYPE_32:
|
50
|
+
return sizeof(struct sdshdr32);
|
51
|
+
case SDS_TYPE_64:
|
52
|
+
return sizeof(struct sdshdr64);
|
53
|
+
}
|
54
|
+
return 0;
|
55
|
+
}
|
56
|
+
|
57
|
+
static inline char sdsReqType(size_t string_size) {
|
58
|
+
if (string_size < 32)
|
59
|
+
return SDS_TYPE_5;
|
60
|
+
if (string_size < 0xff)
|
61
|
+
return SDS_TYPE_8;
|
62
|
+
if (string_size < 0xffff)
|
63
|
+
return SDS_TYPE_16;
|
64
|
+
if (string_size < 0xffffffff)
|
65
|
+
return SDS_TYPE_32;
|
66
|
+
return SDS_TYPE_64;
|
67
|
+
}
|
38
68
|
|
39
69
|
/* Create a new sds string with the content specified by the 'init' pointer
|
40
70
|
* and 'initlen'.
|
@@ -43,26 +73,65 @@
|
|
43
73
|
* The string is always null-termined (all the sds strings are, always) so
|
44
74
|
* even if you create an sds string with:
|
45
75
|
*
|
46
|
-
* mystring = sdsnewlen("abc",3
|
76
|
+
* mystring = sdsnewlen("abc",3);
|
47
77
|
*
|
48
78
|
* You can print the string with printf() as there is an implicit \0 at the
|
49
79
|
* end of the string. However the string is binary safe and can contain
|
50
80
|
* \0 characters in the middle, as the length is stored in the sds header. */
|
51
81
|
sds sdsnewlen(const void *init, size_t initlen) {
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
82
|
+
void *sh;
|
83
|
+
sds s;
|
84
|
+
char type = sdsReqType(initlen);
|
85
|
+
/* Empty strings are usually created in order to append. Use type 8
|
86
|
+
* since type 5 is not good at this. */
|
87
|
+
if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8;
|
88
|
+
int hdrlen = sdsHdrSize(type);
|
89
|
+
unsigned char *fp; /* flags pointer. */
|
90
|
+
|
91
|
+
sh = s_malloc(hdrlen+initlen+1);
|
59
92
|
if (sh == NULL) return NULL;
|
60
|
-
|
61
|
-
|
93
|
+
if (!init)
|
94
|
+
memset(sh, 0, hdrlen+initlen+1);
|
95
|
+
s = (char*)sh+hdrlen;
|
96
|
+
fp = ((unsigned char*)s)-1;
|
97
|
+
switch(type) {
|
98
|
+
case SDS_TYPE_5: {
|
99
|
+
*fp = type | (initlen << SDS_TYPE_BITS);
|
100
|
+
break;
|
101
|
+
}
|
102
|
+
case SDS_TYPE_8: {
|
103
|
+
SDS_HDR_VAR(8,s);
|
104
|
+
sh->len = initlen;
|
105
|
+
sh->alloc = initlen;
|
106
|
+
*fp = type;
|
107
|
+
break;
|
108
|
+
}
|
109
|
+
case SDS_TYPE_16: {
|
110
|
+
SDS_HDR_VAR(16,s);
|
111
|
+
sh->len = initlen;
|
112
|
+
sh->alloc = initlen;
|
113
|
+
*fp = type;
|
114
|
+
break;
|
115
|
+
}
|
116
|
+
case SDS_TYPE_32: {
|
117
|
+
SDS_HDR_VAR(32,s);
|
118
|
+
sh->len = initlen;
|
119
|
+
sh->alloc = initlen;
|
120
|
+
*fp = type;
|
121
|
+
break;
|
122
|
+
}
|
123
|
+
case SDS_TYPE_64: {
|
124
|
+
SDS_HDR_VAR(64,s);
|
125
|
+
sh->len = initlen;
|
126
|
+
sh->alloc = initlen;
|
127
|
+
*fp = type;
|
128
|
+
break;
|
129
|
+
}
|
130
|
+
}
|
62
131
|
if (initlen && init)
|
63
|
-
memcpy(
|
64
|
-
|
65
|
-
return
|
132
|
+
memcpy(s, init, initlen);
|
133
|
+
s[initlen] = '\0';
|
134
|
+
return s;
|
66
135
|
}
|
67
136
|
|
68
137
|
/* Create an empty (zero length) sds string. Even in this case the string
|
@@ -71,7 +140,7 @@ sds sdsempty(void) {
|
|
71
140
|
return sdsnewlen("",0);
|
72
141
|
}
|
73
142
|
|
74
|
-
/* Create a new sds string starting from a null
|
143
|
+
/* Create a new sds string starting from a null terminated C string. */
|
75
144
|
sds sdsnew(const char *init) {
|
76
145
|
size_t initlen = (init == NULL) ? 0 : strlen(init);
|
77
146
|
return sdsnewlen(init, initlen);
|
@@ -85,7 +154,7 @@ sds sdsdup(const sds s) {
|
|
85
154
|
/* Free an sds string. No operation is performed if 's' is NULL. */
|
86
155
|
void sdsfree(sds s) {
|
87
156
|
if (s == NULL) return;
|
88
|
-
|
157
|
+
s_free((char*)s-sdsHdrSize(s[-1]));
|
89
158
|
}
|
90
159
|
|
91
160
|
/* Set the sds string length to the length as obtained with strlen(), so
|
@@ -103,21 +172,17 @@ void sdsfree(sds s) {
|
|
103
172
|
* the output will be "6" as the string was modified but the logical length
|
104
173
|
* remains 6 bytes. */
|
105
174
|
void sdsupdatelen(sds s) {
|
106
|
-
struct sdshdr *sh = (void*) (s-sizeof *sh);;
|
107
175
|
int reallen = strlen(s);
|
108
|
-
|
109
|
-
sh->len = reallen;
|
176
|
+
sdssetlen(s, reallen);
|
110
177
|
}
|
111
178
|
|
112
|
-
/* Modify an sds string
|
179
|
+
/* Modify an sds string in-place to make it empty (zero length).
|
113
180
|
* However all the existing buffer is not discarded but set as free space
|
114
181
|
* so that next append operations will not require allocations up to the
|
115
182
|
* number of bytes previously available. */
|
116
183
|
void sdsclear(sds s) {
|
117
|
-
|
118
|
-
|
119
|
-
sh->len = 0;
|
120
|
-
sh->buf[0] = '\0';
|
184
|
+
sdssetlen(s, 0);
|
185
|
+
s[0] = '\0';
|
121
186
|
}
|
122
187
|
|
123
188
|
/* Enlarge the free space at the end of the sds string so that the caller
|
@@ -127,23 +192,48 @@ void sdsclear(sds s) {
|
|
127
192
|
* Note: this does not change the *length* of the sds string as returned
|
128
193
|
* by sdslen(), but only the free buffer space we have. */
|
129
194
|
sds sdsMakeRoomFor(sds s, size_t addlen) {
|
130
|
-
|
131
|
-
size_t
|
195
|
+
void *sh, *newsh;
|
196
|
+
size_t avail = sdsavail(s);
|
132
197
|
size_t len, newlen;
|
198
|
+
char type, oldtype = s[-1] & SDS_TYPE_MASK;
|
199
|
+
int hdrlen;
|
200
|
+
|
201
|
+
/* Return ASAP if there is enough space left. */
|
202
|
+
if (avail >= addlen) return s;
|
133
203
|
|
134
|
-
if (free >= addlen) return s;
|
135
204
|
len = sdslen(s);
|
136
|
-
sh = (
|
205
|
+
sh = (char*)s-sdsHdrSize(oldtype);
|
137
206
|
newlen = (len+addlen);
|
138
207
|
if (newlen < SDS_MAX_PREALLOC)
|
139
208
|
newlen *= 2;
|
140
209
|
else
|
141
210
|
newlen += SDS_MAX_PREALLOC;
|
142
|
-
newsh = realloc(sh, sizeof *newsh+newlen+1);
|
143
|
-
if (newsh == NULL) return NULL;
|
144
211
|
|
145
|
-
|
146
|
-
|
212
|
+
type = sdsReqType(newlen);
|
213
|
+
|
214
|
+
/* Don't use type 5: the user is appending to the string and type 5 is
|
215
|
+
* not able to remember empty space, so sdsMakeRoomFor() must be called
|
216
|
+
* at every appending operation. */
|
217
|
+
if (type == SDS_TYPE_5) type = SDS_TYPE_8;
|
218
|
+
|
219
|
+
hdrlen = sdsHdrSize(type);
|
220
|
+
if (oldtype==type) {
|
221
|
+
newsh = s_realloc(sh, hdrlen+newlen+1);
|
222
|
+
if (newsh == NULL) return NULL;
|
223
|
+
s = (char*)newsh+hdrlen;
|
224
|
+
} else {
|
225
|
+
/* Since the header size changes, need to move the string forward,
|
226
|
+
* and can't use realloc */
|
227
|
+
newsh = s_malloc(hdrlen+newlen+1);
|
228
|
+
if (newsh == NULL) return NULL;
|
229
|
+
memcpy((char*)newsh+hdrlen, s, len+1);
|
230
|
+
s_free(sh);
|
231
|
+
s = (char*)newsh+hdrlen;
|
232
|
+
s[-1] = type;
|
233
|
+
sdssetlen(s, len);
|
234
|
+
}
|
235
|
+
sdssetalloc(s, newlen);
|
236
|
+
return s;
|
147
237
|
}
|
148
238
|
|
149
239
|
/* Reallocate the sds string so that it has no free space at the end. The
|
@@ -153,12 +243,29 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
|
|
153
243
|
* After the call, the passed sds string is no longer valid and all the
|
154
244
|
* references must be substituted with the new pointer returned by the call. */
|
155
245
|
sds sdsRemoveFreeSpace(sds s) {
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
sh
|
161
|
-
|
246
|
+
void *sh, *newsh;
|
247
|
+
char type, oldtype = s[-1] & SDS_TYPE_MASK;
|
248
|
+
int hdrlen;
|
249
|
+
size_t len = sdslen(s);
|
250
|
+
sh = (char*)s-sdsHdrSize(oldtype);
|
251
|
+
|
252
|
+
type = sdsReqType(len);
|
253
|
+
hdrlen = sdsHdrSize(type);
|
254
|
+
if (oldtype==type) {
|
255
|
+
newsh = s_realloc(sh, hdrlen+len+1);
|
256
|
+
if (newsh == NULL) return NULL;
|
257
|
+
s = (char*)newsh+hdrlen;
|
258
|
+
} else {
|
259
|
+
newsh = s_malloc(hdrlen+len+1);
|
260
|
+
if (newsh == NULL) return NULL;
|
261
|
+
memcpy((char*)newsh+hdrlen, s, len+1);
|
262
|
+
s_free(sh);
|
263
|
+
s = (char*)newsh+hdrlen;
|
264
|
+
s[-1] = type;
|
265
|
+
sdssetlen(s, len);
|
266
|
+
}
|
267
|
+
sdssetalloc(s, len);
|
268
|
+
return s;
|
162
269
|
}
|
163
270
|
|
164
271
|
/* Return the total size of the allocation of the specifed sds string,
|
@@ -169,9 +276,14 @@ sds sdsRemoveFreeSpace(sds s) {
|
|
169
276
|
* 4) The implicit null term.
|
170
277
|
*/
|
171
278
|
size_t sdsAllocSize(sds s) {
|
172
|
-
|
279
|
+
size_t alloc = sdsalloc(s);
|
280
|
+
return sdsHdrSize(s[-1])+alloc+1;
|
281
|
+
}
|
173
282
|
|
174
|
-
|
283
|
+
/* Return the pointer of the actual SDS allocation (normally SDS strings
|
284
|
+
* are referenced by the start of the string buffer). */
|
285
|
+
void *sdsAllocPtr(sds s) {
|
286
|
+
return (void*) (s-sdsHdrSize(s[-1]));
|
175
287
|
}
|
176
288
|
|
177
289
|
/* Increment the sds length and decrements the left free space at the
|
@@ -198,13 +310,44 @@ size_t sdsAllocSize(sds s) {
|
|
198
310
|
* sdsIncrLen(s, nread);
|
199
311
|
*/
|
200
312
|
void sdsIncrLen(sds s, int incr) {
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
313
|
+
unsigned char flags = s[-1];
|
314
|
+
size_t len;
|
315
|
+
switch(flags&SDS_TYPE_MASK) {
|
316
|
+
case SDS_TYPE_5: {
|
317
|
+
unsigned char *fp = ((unsigned char*)s)-1;
|
318
|
+
unsigned char oldlen = SDS_TYPE_5_LEN(flags);
|
319
|
+
assert((incr > 0 && oldlen+incr < 32) || (incr < 0 && oldlen >= (unsigned int)(-incr)));
|
320
|
+
*fp = SDS_TYPE_5 | ((oldlen+incr) << SDS_TYPE_BITS);
|
321
|
+
len = oldlen+incr;
|
322
|
+
break;
|
323
|
+
}
|
324
|
+
case SDS_TYPE_8: {
|
325
|
+
SDS_HDR_VAR(8,s);
|
326
|
+
assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
|
327
|
+
len = (sh->len += incr);
|
328
|
+
break;
|
329
|
+
}
|
330
|
+
case SDS_TYPE_16: {
|
331
|
+
SDS_HDR_VAR(16,s);
|
332
|
+
assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
|
333
|
+
len = (sh->len += incr);
|
334
|
+
break;
|
335
|
+
}
|
336
|
+
case SDS_TYPE_32: {
|
337
|
+
SDS_HDR_VAR(32,s);
|
338
|
+
assert((incr >= 0 && sh->alloc-sh->len >= (unsigned int)incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
|
339
|
+
len = (sh->len += incr);
|
340
|
+
break;
|
341
|
+
}
|
342
|
+
case SDS_TYPE_64: {
|
343
|
+
SDS_HDR_VAR(64,s);
|
344
|
+
assert((incr >= 0 && sh->alloc-sh->len >= (uint64_t)incr) || (incr < 0 && sh->len >= (uint64_t)(-incr)));
|
345
|
+
len = (sh->len += incr);
|
346
|
+
break;
|
347
|
+
}
|
348
|
+
default: len = 0; /* Just to avoid compilation warnings. */
|
349
|
+
}
|
350
|
+
s[len] = '\0';
|
208
351
|
}
|
209
352
|
|
210
353
|
/* Grow the sds to have the specified length. Bytes that were not part of
|
@@ -213,19 +356,15 @@ void sdsIncrLen(sds s, int incr) {
|
|
213
356
|
* if the specified length is smaller than the current length, no operation
|
214
357
|
* is performed. */
|
215
358
|
sds sdsgrowzero(sds s, size_t len) {
|
216
|
-
|
217
|
-
size_t totlen, curlen = sh->len;
|
359
|
+
size_t curlen = sdslen(s);
|
218
360
|
|
219
361
|
if (len <= curlen) return s;
|
220
362
|
s = sdsMakeRoomFor(s,len-curlen);
|
221
363
|
if (s == NULL) return NULL;
|
222
364
|
|
223
365
|
/* Make sure added region doesn't contain garbage */
|
224
|
-
sh = (void*)(s-sizeof *sh);
|
225
366
|
memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */
|
226
|
-
|
227
|
-
sh->len = len;
|
228
|
-
sh->free = totlen-sh->len;
|
367
|
+
sdssetlen(s, len);
|
229
368
|
return s;
|
230
369
|
}
|
231
370
|
|
@@ -235,15 +374,12 @@ sds sdsgrowzero(sds s, size_t len) {
|
|
235
374
|
* After the call, the passed sds string is no longer valid and all the
|
236
375
|
* references must be substituted with the new pointer returned by the call. */
|
237
376
|
sds sdscatlen(sds s, const void *t, size_t len) {
|
238
|
-
struct sdshdr *sh;
|
239
377
|
size_t curlen = sdslen(s);
|
240
378
|
|
241
379
|
s = sdsMakeRoomFor(s,len);
|
242
380
|
if (s == NULL) return NULL;
|
243
|
-
sh = (void*) (s-sizeof *sh);;
|
244
381
|
memcpy(s+curlen, t, len);
|
245
|
-
|
246
|
-
sh->free = sh->free-len;
|
382
|
+
sdssetlen(s, curlen+len);
|
247
383
|
s[curlen+len] = '\0';
|
248
384
|
return s;
|
249
385
|
}
|
@@ -267,19 +403,13 @@ sds sdscatsds(sds s, const sds t) {
|
|
267
403
|
/* Destructively modify the sds string 's' to hold the specified binary
|
268
404
|
* safe string pointed by 't' of length 'len' bytes. */
|
269
405
|
sds sdscpylen(sds s, const char *t, size_t len) {
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
if (totlen < len) {
|
274
|
-
s = sdsMakeRoomFor(s,len-sh->len);
|
406
|
+
if (sdsalloc(s) < len) {
|
407
|
+
s = sdsMakeRoomFor(s,len-sdslen(s));
|
275
408
|
if (s == NULL) return NULL;
|
276
|
-
sh = (void*) (s-sizeof *sh);;
|
277
|
-
totlen = sh->free+sh->len;
|
278
409
|
}
|
279
410
|
memcpy(s, t, len);
|
280
411
|
s[len] = '\0';
|
281
|
-
|
282
|
-
sh->free = totlen-len;
|
412
|
+
sdssetlen(s, len);
|
283
413
|
return s;
|
284
414
|
}
|
285
415
|
|
@@ -293,7 +423,7 @@ sds sdscpy(sds s, const char *t) {
|
|
293
423
|
* conversion. 's' must point to a string with room for at least
|
294
424
|
* SDS_LLSTR_SIZE bytes.
|
295
425
|
*
|
296
|
-
* The function returns the
|
426
|
+
* The function returns the length of the null-terminated string
|
297
427
|
* representation stored at 's'. */
|
298
428
|
#define SDS_LLSTR_SIZE 21
|
299
429
|
int sdsll2str(char *s, long long value) {
|
@@ -356,27 +486,52 @@ int sdsull2str(char *s, unsigned long long v) {
|
|
356
486
|
return l;
|
357
487
|
}
|
358
488
|
|
359
|
-
/*
|
489
|
+
/* Create an sds string from a long long value. It is much faster than:
|
490
|
+
*
|
491
|
+
* sdscatprintf(sdsempty(),"%lld\n", value);
|
492
|
+
*/
|
493
|
+
sds sdsfromlonglong(long long value) {
|
494
|
+
char buf[SDS_LLSTR_SIZE];
|
495
|
+
int len = sdsll2str(buf,value);
|
496
|
+
|
497
|
+
return sdsnewlen(buf,len);
|
498
|
+
}
|
499
|
+
|
500
|
+
/* Like sdscatprintf() but gets va_list instead of being variadic. */
|
360
501
|
sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
|
361
502
|
va_list cpy;
|
362
|
-
char *buf, *t;
|
363
|
-
size_t buflen =
|
503
|
+
char staticbuf[1024], *buf = staticbuf, *t;
|
504
|
+
size_t buflen = strlen(fmt)*2;
|
364
505
|
|
365
|
-
|
366
|
-
|
506
|
+
/* We try to start using a static buffer for speed.
|
507
|
+
* If not possible we revert to heap allocation. */
|
508
|
+
if (buflen > sizeof(staticbuf)) {
|
509
|
+
buf = s_malloc(buflen);
|
367
510
|
if (buf == NULL) return NULL;
|
511
|
+
} else {
|
512
|
+
buflen = sizeof(staticbuf);
|
513
|
+
}
|
514
|
+
|
515
|
+
/* Try with buffers two times bigger every time we fail to
|
516
|
+
* fit the string in the current buffer size. */
|
517
|
+
while(1) {
|
368
518
|
buf[buflen-2] = '\0';
|
369
519
|
va_copy(cpy,ap);
|
370
520
|
vsnprintf(buf, buflen, fmt, cpy);
|
521
|
+
va_end(cpy);
|
371
522
|
if (buf[buflen-2] != '\0') {
|
372
|
-
|
523
|
+
if (buf != staticbuf) s_free(buf);
|
373
524
|
buflen *= 2;
|
525
|
+
buf = s_malloc(buflen);
|
526
|
+
if (buf == NULL) return NULL;
|
374
527
|
continue;
|
375
528
|
}
|
376
529
|
break;
|
377
530
|
}
|
531
|
+
|
532
|
+
/* Finally concat the obtained string to the SDS string and return it. */
|
378
533
|
t = sdscat(s, buf);
|
379
|
-
|
534
|
+
if (buf != staticbuf) s_free(buf);
|
380
535
|
return t;
|
381
536
|
}
|
382
537
|
|
@@ -389,7 +544,7 @@ sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
|
|
389
544
|
* Example:
|
390
545
|
*
|
391
546
|
* s = sdsnew("Sum is: ");
|
392
|
-
* s = sdscatprintf(s,"%d+%d = %d",a,b,a+b)
|
547
|
+
* s = sdscatprintf(s,"%d+%d = %d",a,b,a+b).
|
393
548
|
*
|
394
549
|
* Often you need to create a string from scratch with the printf-alike
|
395
550
|
* format. When this is the need, just use sdsempty() as the target string:
|
@@ -419,29 +574,24 @@ sds sdscatprintf(sds s, const char *fmt, ...) {
|
|
419
574
|
* %I - 64 bit signed integer (long long, int64_t)
|
420
575
|
* %u - unsigned int
|
421
576
|
* %U - 64 bit unsigned integer (unsigned long long, uint64_t)
|
422
|
-
* %T - A size_t variable.
|
423
577
|
* %% - Verbatim "%" character.
|
424
578
|
*/
|
425
579
|
sds sdscatfmt(sds s, char const *fmt, ...) {
|
426
|
-
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
|
427
|
-
size_t initlen = sdslen(s);
|
428
580
|
const char *f = fmt;
|
429
581
|
int i;
|
430
582
|
va_list ap;
|
431
583
|
|
432
584
|
va_start(ap,fmt);
|
433
|
-
|
434
|
-
i = initlen; /* Position of the next byte to write to dest str. */
|
585
|
+
i = sdslen(s); /* Position of the next byte to write to dest str. */
|
435
586
|
while(*f) {
|
436
587
|
char next, *str;
|
437
|
-
|
588
|
+
size_t l;
|
438
589
|
long long num;
|
439
590
|
unsigned long long unum;
|
440
591
|
|
441
592
|
/* Make sure there is always space for at least 1 char. */
|
442
|
-
if (
|
593
|
+
if (sdsavail(s)==0) {
|
443
594
|
s = sdsMakeRoomFor(s,1);
|
444
|
-
sh = (void*) (s-(sizeof(struct sdshdr)));
|
445
595
|
}
|
446
596
|
|
447
597
|
switch(*f) {
|
@@ -453,13 +603,11 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
|
|
453
603
|
case 'S':
|
454
604
|
str = va_arg(ap,char*);
|
455
605
|
l = (next == 's') ? strlen(str) : sdslen(str);
|
456
|
-
if (
|
606
|
+
if (sdsavail(s) < l) {
|
457
607
|
s = sdsMakeRoomFor(s,l);
|
458
|
-
sh = (void*) (s-(sizeof(struct sdshdr)));
|
459
608
|
}
|
460
609
|
memcpy(s+i,str,l);
|
461
|
-
|
462
|
-
sh->free -= l;
|
610
|
+
sdsinclen(s,l);
|
463
611
|
i += l;
|
464
612
|
break;
|
465
613
|
case 'i':
|
@@ -471,49 +619,40 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
|
|
471
619
|
{
|
472
620
|
char buf[SDS_LLSTR_SIZE];
|
473
621
|
l = sdsll2str(buf,num);
|
474
|
-
if (
|
622
|
+
if (sdsavail(s) < l) {
|
475
623
|
s = sdsMakeRoomFor(s,l);
|
476
|
-
sh = (void*) (s-(sizeof(struct sdshdr)));
|
477
624
|
}
|
478
625
|
memcpy(s+i,buf,l);
|
479
|
-
|
480
|
-
sh->free -= l;
|
626
|
+
sdsinclen(s,l);
|
481
627
|
i += l;
|
482
628
|
}
|
483
629
|
break;
|
484
630
|
case 'u':
|
485
631
|
case 'U':
|
486
|
-
case 'T':
|
487
632
|
if (next == 'u')
|
488
633
|
unum = va_arg(ap,unsigned int);
|
489
|
-
else if(next == 'U')
|
490
|
-
unum = va_arg(ap,unsigned long long);
|
491
634
|
else
|
492
|
-
unum = (unsigned long long)
|
635
|
+
unum = va_arg(ap,unsigned long long);
|
493
636
|
{
|
494
637
|
char buf[SDS_LLSTR_SIZE];
|
495
638
|
l = sdsull2str(buf,unum);
|
496
|
-
if (
|
639
|
+
if (sdsavail(s) < l) {
|
497
640
|
s = sdsMakeRoomFor(s,l);
|
498
|
-
sh = (void*) (s-(sizeof(struct sdshdr)));
|
499
641
|
}
|
500
642
|
memcpy(s+i,buf,l);
|
501
|
-
|
502
|
-
sh->free -= l;
|
643
|
+
sdsinclen(s,l);
|
503
644
|
i += l;
|
504
645
|
}
|
505
646
|
break;
|
506
647
|
default: /* Handle %% and generally %<unknown>. */
|
507
648
|
s[i++] = next;
|
508
|
-
|
509
|
-
sh->free -= 1;
|
649
|
+
sdsinclen(s,1);
|
510
650
|
break;
|
511
651
|
}
|
512
652
|
break;
|
513
653
|
default:
|
514
654
|
s[i++] = *f;
|
515
|
-
|
516
|
-
sh->free -= 1;
|
655
|
+
sdsinclen(s,1);
|
517
656
|
break;
|
518
657
|
}
|
519
658
|
f++;
|
@@ -525,7 +664,6 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
|
|
525
664
|
return s;
|
526
665
|
}
|
527
666
|
|
528
|
-
|
529
667
|
/* Remove the part of the string from left and from right composed just of
|
530
668
|
* contiguous characters found in 'cset', that is a null terminted C string.
|
531
669
|
*
|
@@ -535,25 +673,24 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
|
|
535
673
|
* Example:
|
536
674
|
*
|
537
675
|
* s = sdsnew("AA...AA.a.aa.aHelloWorld :::");
|
538
|
-
* s = sdstrim(s,"
|
676
|
+
* s = sdstrim(s,"Aa. :");
|
539
677
|
* printf("%s\n", s);
|
540
678
|
*
|
541
679
|
* Output will be just "Hello World".
|
542
680
|
*/
|
543
|
-
|
544
|
-
struct sdshdr *sh = (void*) (s-sizeof *sh);;
|
681
|
+
sds sdstrim(sds s, const char *cset) {
|
545
682
|
char *start, *end, *sp, *ep;
|
546
683
|
size_t len;
|
547
684
|
|
548
685
|
sp = start = s;
|
549
686
|
ep = end = s+sdslen(s)-1;
|
550
687
|
while(sp <= end && strchr(cset, *sp)) sp++;
|
551
|
-
while(ep >
|
688
|
+
while(ep > sp && strchr(cset, *ep)) ep--;
|
552
689
|
len = (sp > ep) ? 0 : ((ep-sp)+1);
|
553
|
-
if (
|
554
|
-
|
555
|
-
|
556
|
-
|
690
|
+
if (s != sp) memmove(s, sp, len);
|
691
|
+
s[len] = '\0';
|
692
|
+
sdssetlen(s,len);
|
693
|
+
return s;
|
557
694
|
}
|
558
695
|
|
559
696
|
/* Turn the string into a smaller (or equal) string containing only the
|
@@ -573,7 +710,6 @@ void sdstrim(sds s, const char *cset) {
|
|
573
710
|
* sdsrange(s,1,-1); => "ello World"
|
574
711
|
*/
|
575
712
|
void sdsrange(sds s, int start, int end) {
|
576
|
-
struct sdshdr *sh = (void*) (s-sizeof *sh);;
|
577
713
|
size_t newlen, len = sdslen(s);
|
578
714
|
|
579
715
|
if (len == 0) return;
|
@@ -596,10 +732,9 @@ void sdsrange(sds s, int start, int end) {
|
|
596
732
|
} else {
|
597
733
|
start = 0;
|
598
734
|
}
|
599
|
-
if (start && newlen) memmove(
|
600
|
-
|
601
|
-
|
602
|
-
sh->len = newlen;
|
735
|
+
if (start && newlen) memmove(s, s+start, newlen);
|
736
|
+
s[newlen] = 0;
|
737
|
+
sdssetlen(s,newlen);
|
603
738
|
}
|
604
739
|
|
605
740
|
/* Apply tolower() to every character of the sds string 's'. */
|
@@ -620,8 +755,8 @@ void sdstoupper(sds s) {
|
|
620
755
|
*
|
621
756
|
* Return value:
|
622
757
|
*
|
623
|
-
*
|
624
|
-
*
|
758
|
+
* positive if s1 > s2.
|
759
|
+
* negative if s1 < s2.
|
625
760
|
* 0 if s1 and s2 are exactly the same binary string.
|
626
761
|
*
|
627
762
|
* If two strings share exactly the same prefix, but one of the two has
|
@@ -661,7 +796,7 @@ sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count
|
|
661
796
|
|
662
797
|
if (seplen < 1 || len < 0) return NULL;
|
663
798
|
|
664
|
-
tokens =
|
799
|
+
tokens = s_malloc(sizeof(sds)*slots);
|
665
800
|
if (tokens == NULL) return NULL;
|
666
801
|
|
667
802
|
if (len == 0) {
|
@@ -674,7 +809,7 @@ sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count
|
|
674
809
|
sds *newtokens;
|
675
810
|
|
676
811
|
slots *= 2;
|
677
|
-
newtokens =
|
812
|
+
newtokens = s_realloc(tokens,sizeof(sds)*slots);
|
678
813
|
if (newtokens == NULL) goto cleanup;
|
679
814
|
tokens = newtokens;
|
680
815
|
}
|
@@ -698,7 +833,7 @@ cleanup:
|
|
698
833
|
{
|
699
834
|
int i;
|
700
835
|
for (i = 0; i < elements; i++) sdsfree(tokens[i]);
|
701
|
-
|
836
|
+
s_free(tokens);
|
702
837
|
*count = 0;
|
703
838
|
return NULL;
|
704
839
|
}
|
@@ -709,26 +844,7 @@ void sdsfreesplitres(sds *tokens, int count) {
|
|
709
844
|
if (!tokens) return;
|
710
845
|
while(count--)
|
711
846
|
sdsfree(tokens[count]);
|
712
|
-
|
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
|
-
*/
|
719
|
-
sds 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));
|
847
|
+
s_free(tokens);
|
732
848
|
}
|
733
849
|
|
734
850
|
/* Append to the sds string "s" an escaped string representation where
|
@@ -902,13 +1018,13 @@ sds *sdssplitargs(const char *line, int *argc) {
|
|
902
1018
|
if (*p) p++;
|
903
1019
|
}
|
904
1020
|
/* add the token to the vector */
|
905
|
-
vector =
|
1021
|
+
vector = s_realloc(vector,((*argc)+1)*sizeof(char*));
|
906
1022
|
vector[*argc] = current;
|
907
1023
|
(*argc)++;
|
908
1024
|
current = NULL;
|
909
1025
|
} else {
|
910
1026
|
/* Even on empty input string return something not NULL. */
|
911
|
-
if (vector == NULL) vector =
|
1027
|
+
if (vector == NULL) vector = s_malloc(sizeof(void*));
|
912
1028
|
return vector;
|
913
1029
|
}
|
914
1030
|
}
|
@@ -916,7 +1032,7 @@ sds *sdssplitargs(const char *line, int *argc) {
|
|
916
1032
|
err:
|
917
1033
|
while((*argc)--)
|
918
1034
|
sdsfree(vector[*argc]);
|
919
|
-
|
1035
|
+
s_free(vector);
|
920
1036
|
if (current) sdsfree(current);
|
921
1037
|
*argc = 0;
|
922
1038
|
return NULL;
|
@@ -947,13 +1063,13 @@ sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
|
|
947
1063
|
|
948
1064
|
/* Join an array of C strings using the specified separator (also a C string).
|
949
1065
|
* Returns the result as an sds string. */
|
950
|
-
sds sdsjoin(char **argv, int argc, char *sep
|
1066
|
+
sds sdsjoin(char **argv, int argc, char *sep) {
|
951
1067
|
sds join = sdsempty();
|
952
1068
|
int j;
|
953
1069
|
|
954
1070
|
for (j = 0; j < argc; j++) {
|
955
1071
|
join = sdscat(join, argv[j]);
|
956
|
-
if (j != argc-1) join =
|
1072
|
+
if (j != argc-1) join = sdscat(join,sep);
|
957
1073
|
}
|
958
1074
|
return join;
|
959
1075
|
}
|
@@ -970,13 +1086,23 @@ sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen) {
|
|
970
1086
|
return join;
|
971
1087
|
}
|
972
1088
|
|
973
|
-
|
1089
|
+
/* Wrappers to the allocators used by SDS. Note that SDS will actually
|
1090
|
+
* just use the macros defined into sdsalloc.h in order to avoid to pay
|
1091
|
+
* the overhead of function calls. Here we define these wrappers only for
|
1092
|
+
* the programs SDS is linked to, if they want to touch the SDS internals
|
1093
|
+
* even if they use a different allocator. */
|
1094
|
+
void *sds_malloc(size_t size) { return s_malloc(size); }
|
1095
|
+
void *sds_realloc(void *ptr, size_t size) { return s_realloc(ptr,size); }
|
1096
|
+
void sds_free(void *ptr) { s_free(ptr); }
|
1097
|
+
|
1098
|
+
#if defined(SDS_TEST_MAIN)
|
974
1099
|
#include <stdio.h>
|
975
1100
|
#include "testhelp.h"
|
1101
|
+
#include "limits.h"
|
976
1102
|
|
977
|
-
|
1103
|
+
#define UNUSED(x) (void)(x)
|
1104
|
+
int sdsTest(void) {
|
978
1105
|
{
|
979
|
-
struct sdshdr *sh;
|
980
1106
|
sds x = sdsnew("foo"), y;
|
981
1107
|
|
982
1108
|
test_cond("Create a string and obtain the length",
|
@@ -1003,7 +1129,35 @@ int main(void) {
|
|
1003
1129
|
sdsfree(x);
|
1004
1130
|
x = sdscatprintf(sdsempty(),"%d",123);
|
1005
1131
|
test_cond("sdscatprintf() seems working in the base case",
|
1006
|
-
sdslen(x) == 3 && memcmp(x,"123\0",4) ==0)
|
1132
|
+
sdslen(x) == 3 && memcmp(x,"123\0",4) == 0)
|
1133
|
+
|
1134
|
+
sdsfree(x);
|
1135
|
+
x = sdsnew("--");
|
1136
|
+
x = sdscatfmt(x, "Hello %s World %I,%I--", "Hi!", LLONG_MIN,LLONG_MAX);
|
1137
|
+
test_cond("sdscatfmt() seems working in the base case",
|
1138
|
+
sdslen(x) == 60 &&
|
1139
|
+
memcmp(x,"--Hello Hi! World -9223372036854775808,"
|
1140
|
+
"9223372036854775807--",60) == 0)
|
1141
|
+
printf("[%s]\n",x);
|
1142
|
+
|
1143
|
+
sdsfree(x);
|
1144
|
+
x = sdsnew("--");
|
1145
|
+
x = sdscatfmt(x, "%u,%U--", UINT_MAX, ULLONG_MAX);
|
1146
|
+
test_cond("sdscatfmt() seems working with unsigned numbers",
|
1147
|
+
sdslen(x) == 35 &&
|
1148
|
+
memcmp(x,"--4294967295,18446744073709551615--",35) == 0)
|
1149
|
+
|
1150
|
+
sdsfree(x);
|
1151
|
+
x = sdsnew(" x ");
|
1152
|
+
sdstrim(x," x");
|
1153
|
+
test_cond("sdstrim() works when all chars match",
|
1154
|
+
sdslen(x) == 0)
|
1155
|
+
|
1156
|
+
sdsfree(x);
|
1157
|
+
x = sdsnew(" x ");
|
1158
|
+
sdstrim(x," ");
|
1159
|
+
test_cond("sdstrim() works when a single char remains",
|
1160
|
+
sdslen(x) == 1 && x[0] == 'x')
|
1007
1161
|
|
1008
1162
|
sdsfree(x);
|
1009
1163
|
x = sdsnew("xxciaoyyy");
|
@@ -1072,24 +1226,47 @@ int main(void) {
|
|
1072
1226
|
memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0)
|
1073
1227
|
|
1074
1228
|
{
|
1075
|
-
int oldfree;
|
1229
|
+
unsigned int oldfree;
|
1230
|
+
char *p;
|
1231
|
+
int step = 10, j, i;
|
1076
1232
|
|
1077
1233
|
sdsfree(x);
|
1234
|
+
sdsfree(y);
|
1078
1235
|
x = sdsnew("0");
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1236
|
+
test_cond("sdsnew() free/len buffers", sdslen(x) == 1 && sdsavail(x) == 0);
|
1237
|
+
|
1238
|
+
/* Run the test a few times in order to hit the first two
|
1239
|
+
* SDS header types. */
|
1240
|
+
for (i = 0; i < 10; i++) {
|
1241
|
+
int oldlen = sdslen(x);
|
1242
|
+
x = sdsMakeRoomFor(x,step);
|
1243
|
+
int type = x[-1]&SDS_TYPE_MASK;
|
1244
|
+
|
1245
|
+
test_cond("sdsMakeRoomFor() len", sdslen(x) == oldlen);
|
1246
|
+
if (type != SDS_TYPE_5) {
|
1247
|
+
test_cond("sdsMakeRoomFor() free", sdsavail(x) >= step);
|
1248
|
+
oldfree = sdsavail(x);
|
1249
|
+
}
|
1250
|
+
p = x+oldlen;
|
1251
|
+
for (j = 0; j < step; j++) {
|
1252
|
+
p[j] = 'A'+j;
|
1253
|
+
}
|
1254
|
+
sdsIncrLen(x,step);
|
1255
|
+
}
|
1256
|
+
test_cond("sdsMakeRoomFor() content",
|
1257
|
+
memcmp("0ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ",x,101) == 0);
|
1258
|
+
test_cond("sdsMakeRoomFor() final length",sdslen(x)==101);
|
1259
|
+
|
1260
|
+
sdsfree(x);
|
1090
1261
|
}
|
1091
1262
|
}
|
1092
1263
|
test_report()
|
1093
1264
|
return 0;
|
1094
1265
|
}
|
1095
1266
|
#endif
|
1267
|
+
|
1268
|
+
#ifdef SDS_TEST_MAIN
|
1269
|
+
int main(void) {
|
1270
|
+
return sdsTest();
|
1271
|
+
}
|
1272
|
+
#endif
|