hiredis 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,116 +0,0 @@
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
@@ -1,1095 +0,0 @@
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. */
51
- sds 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. */
70
- sds sdsempty(void) {
71
- return sdsnewlen("",0);
72
- }
73
-
74
- /* Create a new sds string starting from a null termined C string. */
75
- sds 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. */
81
- sds 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. */
86
- void 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. */
105
- void 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. */
116
- void 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. */
129
- sds 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. */
155
- sds 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
- */
171
- size_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
- */
200
- void 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. */
215
- sds 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. */
237
- sds 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. */
255
- sds 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. */
263
- sds 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. */
269
- sds 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(). */
288
- sds 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
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
-
359
- /* Like sdscatpritf() but gets va_list instead of being variadic. */
360
- sds 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
- */
399
- sds 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
- */
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
-
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
- */
543
- void 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
- */
575
- void 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'. */
606
- void 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'. */
613
- void 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. */
630
- int 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
- */
658
- sds *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
-
697
- cleanup:
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. */
708
- void 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
- */
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));
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. */
740
- sds 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. */
767
- int 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 */
774
- int 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
- */
815
- sds *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
-
916
- err:
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. */
934
- sds 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. */
950
- sds 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. */
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);
969
- }
970
- return join;
971
- }
972
-
973
- #ifdef SDS_TEST_MAIN
974
- #include <stdio.h>
975
- #include "testhelp.h"
976
-
977
- int 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