methodmissing_hiredis 0.4.6
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.
- data/COPYING +28 -0
- data/Rakefile +45 -0
- data/ext/hiredis_ext/connection.c +472 -0
- data/ext/hiredis_ext/extconf.rb +17 -0
- data/ext/hiredis_ext/hiredis_ext.c +13 -0
- data/ext/hiredis_ext/hiredis_ext.h +37 -0
- data/ext/hiredis_ext/reader.c +114 -0
- data/lib/hiredis.rb +2 -0
- data/lib/hiredis/connection.rb +10 -0
- data/lib/hiredis/ext/connection.rb +29 -0
- data/lib/hiredis/ext/reader.rb +2 -0
- data/lib/hiredis/reader.rb +10 -0
- data/lib/hiredis/ruby/connection.rb +298 -0
- data/lib/hiredis/ruby/reader.rb +183 -0
- data/lib/hiredis/version.rb +3 -0
- data/vendor/hiredis/COPYING +29 -0
- data/vendor/hiredis/Makefile +148 -0
- data/vendor/hiredis/async.c +647 -0
- data/vendor/hiredis/async.h +125 -0
- data/vendor/hiredis/dict.c +338 -0
- data/vendor/hiredis/dict.h +126 -0
- data/vendor/hiredis/fmacros.h +16 -0
- data/vendor/hiredis/hiredis.c +1315 -0
- data/vendor/hiredis/hiredis.h +210 -0
- data/vendor/hiredis/net.c +292 -0
- data/vendor/hiredis/net.h +47 -0
- data/vendor/hiredis/sds.c +605 -0
- data/vendor/hiredis/sds.h +88 -0
- data/vendor/hiredis/test.c +686 -0
- metadata +110 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
/* Extracted from anet.c to work properly with Hiredis error reporting.
|
2
|
+
*
|
3
|
+
* Copyright (c) 2006-2011, Salvatore Sanfilippo <antirez at gmail dot com>
|
4
|
+
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
5
|
+
*
|
6
|
+
* All rights reserved.
|
7
|
+
*
|
8
|
+
* Redistribution and use in source and binary forms, with or without
|
9
|
+
* modification, are permitted provided that the following conditions are met:
|
10
|
+
*
|
11
|
+
* * Redistributions of source code must retain the above copyright notice,
|
12
|
+
* this list of conditions and the following disclaimer.
|
13
|
+
* * Redistributions in binary form must reproduce the above copyright
|
14
|
+
* notice, this list of conditions and the following disclaimer in the
|
15
|
+
* documentation and/or other materials provided with the distribution.
|
16
|
+
* * Neither the name of Redis nor the names of its contributors may be used
|
17
|
+
* to endorse or promote products derived from this software without
|
18
|
+
* specific prior written permission.
|
19
|
+
*
|
20
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
23
|
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
24
|
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
25
|
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
26
|
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
27
|
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
28
|
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
29
|
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
30
|
+
* POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
*/
|
32
|
+
|
33
|
+
#ifndef __NET_H
|
34
|
+
#define __NET_H
|
35
|
+
|
36
|
+
#include "hiredis.h"
|
37
|
+
|
38
|
+
#if defined(__sun)
|
39
|
+
#define AF_LOCAL AF_UNIX
|
40
|
+
#endif
|
41
|
+
|
42
|
+
int redisCheckSocketError(redisContext *c, int fd);
|
43
|
+
int redisContextSetTimeout(redisContext *c, struct timeval tv);
|
44
|
+
int redisContextConnectTcp(redisContext *c, const char *addr, int port, struct timeval *timeout);
|
45
|
+
int redisContextConnectUnix(redisContext *c, const char *path, struct timeval *timeout);
|
46
|
+
|
47
|
+
#endif
|
@@ -0,0 +1,605 @@
|
|
1
|
+
/* SDSLib, A C dynamic strings library
|
2
|
+
*
|
3
|
+
* Copyright (c) 2006-2010, 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 "sds.h"
|
36
|
+
|
37
|
+
#ifdef SDS_ABORT_ON_OOM
|
38
|
+
static void sdsOomAbort(void) {
|
39
|
+
fprintf(stderr,"SDS: Out Of Memory (SDS_ABORT_ON_OOM defined)\n");
|
40
|
+
abort();
|
41
|
+
}
|
42
|
+
#endif
|
43
|
+
|
44
|
+
sds sdsnewlen(const void *init, size_t initlen) {
|
45
|
+
struct sdshdr *sh;
|
46
|
+
|
47
|
+
sh = malloc(sizeof(struct sdshdr)+initlen+1);
|
48
|
+
#ifdef SDS_ABORT_ON_OOM
|
49
|
+
if (sh == NULL) sdsOomAbort();
|
50
|
+
#else
|
51
|
+
if (sh == NULL) return NULL;
|
52
|
+
#endif
|
53
|
+
sh->len = initlen;
|
54
|
+
sh->free = 0;
|
55
|
+
if (initlen) {
|
56
|
+
if (init) memcpy(sh->buf, init, initlen);
|
57
|
+
else memset(sh->buf,0,initlen);
|
58
|
+
}
|
59
|
+
sh->buf[initlen] = '\0';
|
60
|
+
return (char*)sh->buf;
|
61
|
+
}
|
62
|
+
|
63
|
+
sds sdsempty(void) {
|
64
|
+
return sdsnewlen("",0);
|
65
|
+
}
|
66
|
+
|
67
|
+
sds sdsnew(const char *init) {
|
68
|
+
size_t initlen = (init == NULL) ? 0 : strlen(init);
|
69
|
+
return sdsnewlen(init, initlen);
|
70
|
+
}
|
71
|
+
|
72
|
+
sds sdsdup(const sds s) {
|
73
|
+
return sdsnewlen(s, sdslen(s));
|
74
|
+
}
|
75
|
+
|
76
|
+
void sdsfree(sds s) {
|
77
|
+
if (s == NULL) return;
|
78
|
+
free(s-sizeof(struct sdshdr));
|
79
|
+
}
|
80
|
+
|
81
|
+
void sdsupdatelen(sds s) {
|
82
|
+
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
|
83
|
+
int reallen = strlen(s);
|
84
|
+
sh->free += (sh->len-reallen);
|
85
|
+
sh->len = reallen;
|
86
|
+
}
|
87
|
+
|
88
|
+
static sds sdsMakeRoomFor(sds s, size_t addlen) {
|
89
|
+
struct sdshdr *sh, *newsh;
|
90
|
+
size_t free = sdsavail(s);
|
91
|
+
size_t len, newlen;
|
92
|
+
|
93
|
+
if (free >= addlen) return s;
|
94
|
+
len = sdslen(s);
|
95
|
+
sh = (void*) (s-(sizeof(struct sdshdr)));
|
96
|
+
newlen = (len+addlen)*2;
|
97
|
+
newsh = realloc(sh, sizeof(struct sdshdr)+newlen+1);
|
98
|
+
#ifdef SDS_ABORT_ON_OOM
|
99
|
+
if (newsh == NULL) sdsOomAbort();
|
100
|
+
#else
|
101
|
+
if (newsh == NULL) return NULL;
|
102
|
+
#endif
|
103
|
+
|
104
|
+
newsh->free = newlen - len;
|
105
|
+
return newsh->buf;
|
106
|
+
}
|
107
|
+
|
108
|
+
/* Grow the sds to have the specified length. Bytes that were not part of
|
109
|
+
* the original length of the sds will be set to zero. */
|
110
|
+
sds sdsgrowzero(sds s, size_t len) {
|
111
|
+
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
|
112
|
+
size_t totlen, curlen = sh->len;
|
113
|
+
|
114
|
+
if (len <= curlen) return s;
|
115
|
+
s = sdsMakeRoomFor(s,len-curlen);
|
116
|
+
if (s == NULL) return NULL;
|
117
|
+
|
118
|
+
/* Make sure added region doesn't contain garbage */
|
119
|
+
sh = (void*)(s-(sizeof(struct sdshdr)));
|
120
|
+
memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */
|
121
|
+
totlen = sh->len+sh->free;
|
122
|
+
sh->len = len;
|
123
|
+
sh->free = totlen-sh->len;
|
124
|
+
return s;
|
125
|
+
}
|
126
|
+
|
127
|
+
sds sdscatlen(sds s, const void *t, size_t len) {
|
128
|
+
struct sdshdr *sh;
|
129
|
+
size_t curlen = sdslen(s);
|
130
|
+
|
131
|
+
s = sdsMakeRoomFor(s,len);
|
132
|
+
if (s == NULL) return NULL;
|
133
|
+
sh = (void*) (s-(sizeof(struct sdshdr)));
|
134
|
+
memcpy(s+curlen, t, len);
|
135
|
+
sh->len = curlen+len;
|
136
|
+
sh->free = sh->free-len;
|
137
|
+
s[curlen+len] = '\0';
|
138
|
+
return s;
|
139
|
+
}
|
140
|
+
|
141
|
+
sds sdscat(sds s, const char *t) {
|
142
|
+
return sdscatlen(s, t, strlen(t));
|
143
|
+
}
|
144
|
+
|
145
|
+
sds sdscpylen(sds s, char *t, size_t len) {
|
146
|
+
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
|
147
|
+
size_t totlen = sh->free+sh->len;
|
148
|
+
|
149
|
+
if (totlen < len) {
|
150
|
+
s = sdsMakeRoomFor(s,len-sh->len);
|
151
|
+
if (s == NULL) return NULL;
|
152
|
+
sh = (void*) (s-(sizeof(struct sdshdr)));
|
153
|
+
totlen = sh->free+sh->len;
|
154
|
+
}
|
155
|
+
memcpy(s, t, len);
|
156
|
+
s[len] = '\0';
|
157
|
+
sh->len = len;
|
158
|
+
sh->free = totlen-len;
|
159
|
+
return s;
|
160
|
+
}
|
161
|
+
|
162
|
+
sds sdscpy(sds s, char *t) {
|
163
|
+
return sdscpylen(s, t, strlen(t));
|
164
|
+
}
|
165
|
+
|
166
|
+
sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
|
167
|
+
va_list cpy;
|
168
|
+
char *buf, *t;
|
169
|
+
size_t buflen = 16;
|
170
|
+
|
171
|
+
while(1) {
|
172
|
+
buf = malloc(buflen);
|
173
|
+
#ifdef SDS_ABORT_ON_OOM
|
174
|
+
if (buf == NULL) sdsOomAbort();
|
175
|
+
#else
|
176
|
+
if (buf == NULL) return NULL;
|
177
|
+
#endif
|
178
|
+
buf[buflen-2] = '\0';
|
179
|
+
va_copy(cpy,ap);
|
180
|
+
vsnprintf(buf, buflen, fmt, cpy);
|
181
|
+
if (buf[buflen-2] != '\0') {
|
182
|
+
free(buf);
|
183
|
+
buflen *= 2;
|
184
|
+
continue;
|
185
|
+
}
|
186
|
+
break;
|
187
|
+
}
|
188
|
+
t = sdscat(s, buf);
|
189
|
+
free(buf);
|
190
|
+
return t;
|
191
|
+
}
|
192
|
+
|
193
|
+
sds sdscatprintf(sds s, const char *fmt, ...) {
|
194
|
+
va_list ap;
|
195
|
+
char *t;
|
196
|
+
va_start(ap, fmt);
|
197
|
+
t = sdscatvprintf(s,fmt,ap);
|
198
|
+
va_end(ap);
|
199
|
+
return t;
|
200
|
+
}
|
201
|
+
|
202
|
+
sds sdstrim(sds s, const char *cset) {
|
203
|
+
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
|
204
|
+
char *start, *end, *sp, *ep;
|
205
|
+
size_t len;
|
206
|
+
|
207
|
+
sp = start = s;
|
208
|
+
ep = end = s+sdslen(s)-1;
|
209
|
+
while(sp <= end && strchr(cset, *sp)) sp++;
|
210
|
+
while(ep > start && strchr(cset, *ep)) ep--;
|
211
|
+
len = (sp > ep) ? 0 : ((ep-sp)+1);
|
212
|
+
if (sh->buf != sp) memmove(sh->buf, sp, len);
|
213
|
+
sh->buf[len] = '\0';
|
214
|
+
sh->free = sh->free+(sh->len-len);
|
215
|
+
sh->len = len;
|
216
|
+
return s;
|
217
|
+
}
|
218
|
+
|
219
|
+
sds sdsrange(sds s, int start, int end) {
|
220
|
+
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
|
221
|
+
size_t newlen, len = sdslen(s);
|
222
|
+
|
223
|
+
if (len == 0) return s;
|
224
|
+
if (start < 0) {
|
225
|
+
start = len+start;
|
226
|
+
if (start < 0) start = 0;
|
227
|
+
}
|
228
|
+
if (end < 0) {
|
229
|
+
end = len+end;
|
230
|
+
if (end < 0) end = 0;
|
231
|
+
}
|
232
|
+
newlen = (start > end) ? 0 : (end-start)+1;
|
233
|
+
if (newlen != 0) {
|
234
|
+
if (start >= (signed)len) {
|
235
|
+
newlen = 0;
|
236
|
+
} else if (end >= (signed)len) {
|
237
|
+
end = len-1;
|
238
|
+
newlen = (start > end) ? 0 : (end-start)+1;
|
239
|
+
}
|
240
|
+
} else {
|
241
|
+
start = 0;
|
242
|
+
}
|
243
|
+
if (start && newlen) memmove(sh->buf, sh->buf+start, newlen);
|
244
|
+
sh->buf[newlen] = 0;
|
245
|
+
sh->free = sh->free+(sh->len-newlen);
|
246
|
+
sh->len = newlen;
|
247
|
+
return s;
|
248
|
+
}
|
249
|
+
|
250
|
+
void sdstolower(sds s) {
|
251
|
+
int len = sdslen(s), j;
|
252
|
+
|
253
|
+
for (j = 0; j < len; j++) s[j] = tolower(s[j]);
|
254
|
+
}
|
255
|
+
|
256
|
+
void sdstoupper(sds s) {
|
257
|
+
int len = sdslen(s), j;
|
258
|
+
|
259
|
+
for (j = 0; j < len; j++) s[j] = toupper(s[j]);
|
260
|
+
}
|
261
|
+
|
262
|
+
int sdscmp(sds s1, sds s2) {
|
263
|
+
size_t l1, l2, minlen;
|
264
|
+
int cmp;
|
265
|
+
|
266
|
+
l1 = sdslen(s1);
|
267
|
+
l2 = sdslen(s2);
|
268
|
+
minlen = (l1 < l2) ? l1 : l2;
|
269
|
+
cmp = memcmp(s1,s2,minlen);
|
270
|
+
if (cmp == 0) return l1-l2;
|
271
|
+
return cmp;
|
272
|
+
}
|
273
|
+
|
274
|
+
/* Split 's' with separator in 'sep'. An array
|
275
|
+
* of sds strings is returned. *count will be set
|
276
|
+
* by reference to the number of tokens returned.
|
277
|
+
*
|
278
|
+
* On out of memory, zero length string, zero length
|
279
|
+
* separator, NULL is returned.
|
280
|
+
*
|
281
|
+
* Note that 'sep' is able to split a string using
|
282
|
+
* a multi-character separator. For example
|
283
|
+
* sdssplit("foo_-_bar","_-_"); will return two
|
284
|
+
* elements "foo" and "bar".
|
285
|
+
*
|
286
|
+
* This version of the function is binary-safe but
|
287
|
+
* requires length arguments. sdssplit() is just the
|
288
|
+
* same function but for zero-terminated strings.
|
289
|
+
*/
|
290
|
+
sds *sdssplitlen(char *s, int len, char *sep, int seplen, int *count) {
|
291
|
+
int elements = 0, slots = 5, start = 0, j;
|
292
|
+
|
293
|
+
sds *tokens = malloc(sizeof(sds)*slots);
|
294
|
+
#ifdef SDS_ABORT_ON_OOM
|
295
|
+
if (tokens == NULL) sdsOomAbort();
|
296
|
+
#endif
|
297
|
+
if (seplen < 1 || len < 0 || tokens == NULL) return NULL;
|
298
|
+
if (len == 0) {
|
299
|
+
*count = 0;
|
300
|
+
return tokens;
|
301
|
+
}
|
302
|
+
for (j = 0; j < (len-(seplen-1)); j++) {
|
303
|
+
/* make sure there is room for the next element and the final one */
|
304
|
+
if (slots < elements+2) {
|
305
|
+
sds *newtokens;
|
306
|
+
|
307
|
+
slots *= 2;
|
308
|
+
newtokens = realloc(tokens,sizeof(sds)*slots);
|
309
|
+
if (newtokens == NULL) {
|
310
|
+
#ifdef SDS_ABORT_ON_OOM
|
311
|
+
sdsOomAbort();
|
312
|
+
#else
|
313
|
+
goto cleanup;
|
314
|
+
#endif
|
315
|
+
}
|
316
|
+
tokens = newtokens;
|
317
|
+
}
|
318
|
+
/* search the separator */
|
319
|
+
if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0)) {
|
320
|
+
tokens[elements] = sdsnewlen(s+start,j-start);
|
321
|
+
if (tokens[elements] == NULL) {
|
322
|
+
#ifdef SDS_ABORT_ON_OOM
|
323
|
+
sdsOomAbort();
|
324
|
+
#else
|
325
|
+
goto cleanup;
|
326
|
+
#endif
|
327
|
+
}
|
328
|
+
elements++;
|
329
|
+
start = j+seplen;
|
330
|
+
j = j+seplen-1; /* skip the separator */
|
331
|
+
}
|
332
|
+
}
|
333
|
+
/* Add the final element. We are sure there is room in the tokens array. */
|
334
|
+
tokens[elements] = sdsnewlen(s+start,len-start);
|
335
|
+
if (tokens[elements] == NULL) {
|
336
|
+
#ifdef SDS_ABORT_ON_OOM
|
337
|
+
sdsOomAbort();
|
338
|
+
#else
|
339
|
+
goto cleanup;
|
340
|
+
#endif
|
341
|
+
}
|
342
|
+
elements++;
|
343
|
+
*count = elements;
|
344
|
+
return tokens;
|
345
|
+
|
346
|
+
#ifndef SDS_ABORT_ON_OOM
|
347
|
+
cleanup:
|
348
|
+
{
|
349
|
+
int i;
|
350
|
+
for (i = 0; i < elements; i++) sdsfree(tokens[i]);
|
351
|
+
free(tokens);
|
352
|
+
return NULL;
|
353
|
+
}
|
354
|
+
#endif
|
355
|
+
}
|
356
|
+
|
357
|
+
void sdsfreesplitres(sds *tokens, int count) {
|
358
|
+
if (!tokens) return;
|
359
|
+
while(count--)
|
360
|
+
sdsfree(tokens[count]);
|
361
|
+
free(tokens);
|
362
|
+
}
|
363
|
+
|
364
|
+
sds sdsfromlonglong(long long value) {
|
365
|
+
char buf[32], *p;
|
366
|
+
unsigned long long v;
|
367
|
+
|
368
|
+
v = (value < 0) ? -value : value;
|
369
|
+
p = buf+31; /* point to the last character */
|
370
|
+
do {
|
371
|
+
*p-- = '0'+(v%10);
|
372
|
+
v /= 10;
|
373
|
+
} while(v);
|
374
|
+
if (value < 0) *p-- = '-';
|
375
|
+
p++;
|
376
|
+
return sdsnewlen(p,32-(p-buf));
|
377
|
+
}
|
378
|
+
|
379
|
+
sds sdscatrepr(sds s, char *p, size_t len) {
|
380
|
+
s = sdscatlen(s,"\"",1);
|
381
|
+
if (s == NULL) return NULL;
|
382
|
+
|
383
|
+
while(len--) {
|
384
|
+
switch(*p) {
|
385
|
+
case '\\':
|
386
|
+
case '"':
|
387
|
+
s = sdscatprintf(s,"\\%c",*p);
|
388
|
+
break;
|
389
|
+
case '\n': s = sdscatlen(s,"\\n",2); break;
|
390
|
+
case '\r': s = sdscatlen(s,"\\r",2); break;
|
391
|
+
case '\t': s = sdscatlen(s,"\\t",2); break;
|
392
|
+
case '\a': s = sdscatlen(s,"\\a",2); break;
|
393
|
+
case '\b': s = sdscatlen(s,"\\b",2); break;
|
394
|
+
default:
|
395
|
+
if (isprint(*p))
|
396
|
+
s = sdscatprintf(s,"%c",*p);
|
397
|
+
else
|
398
|
+
s = sdscatprintf(s,"\\x%02x",(unsigned char)*p);
|
399
|
+
break;
|
400
|
+
}
|
401
|
+
p++;
|
402
|
+
if (s == NULL) return NULL;
|
403
|
+
}
|
404
|
+
return sdscatlen(s,"\"",1);
|
405
|
+
}
|
406
|
+
|
407
|
+
/* Split a line into arguments, where every argument can be in the
|
408
|
+
* following programming-language REPL-alike form:
|
409
|
+
*
|
410
|
+
* foo bar "newline are supported\n" and "\xff\x00otherstuff"
|
411
|
+
*
|
412
|
+
* The number of arguments is stored into *argc, and an array
|
413
|
+
* of sds is returned. The caller should sdsfree() all the returned
|
414
|
+
* strings and finally free() the array itself.
|
415
|
+
*
|
416
|
+
* Note that sdscatrepr() is able to convert back a string into
|
417
|
+
* a quoted string in the same format sdssplitargs() is able to parse.
|
418
|
+
*/
|
419
|
+
sds *sdssplitargs(char *line, int *argc) {
|
420
|
+
char *p = line;
|
421
|
+
char *current = NULL;
|
422
|
+
char **vector = NULL, **_vector = NULL;
|
423
|
+
|
424
|
+
*argc = 0;
|
425
|
+
while(1) {
|
426
|
+
/* skip blanks */
|
427
|
+
while(*p && isspace(*p)) p++;
|
428
|
+
if (*p) {
|
429
|
+
/* get a token */
|
430
|
+
int inq=0; /* set to 1 if we are in "quotes" */
|
431
|
+
int done=0;
|
432
|
+
|
433
|
+
if (current == NULL) {
|
434
|
+
current = sdsempty();
|
435
|
+
if (current == NULL) goto err;
|
436
|
+
}
|
437
|
+
|
438
|
+
while(!done) {
|
439
|
+
if (inq) {
|
440
|
+
if (*p == '\\' && *(p+1)) {
|
441
|
+
char c;
|
442
|
+
|
443
|
+
p++;
|
444
|
+
switch(*p) {
|
445
|
+
case 'n': c = '\n'; break;
|
446
|
+
case 'r': c = '\r'; break;
|
447
|
+
case 't': c = '\t'; break;
|
448
|
+
case 'b': c = '\b'; break;
|
449
|
+
case 'a': c = '\a'; break;
|
450
|
+
default: c = *p; break;
|
451
|
+
}
|
452
|
+
current = sdscatlen(current,&c,1);
|
453
|
+
} else if (*p == '"') {
|
454
|
+
/* closing quote must be followed by a space */
|
455
|
+
if (*(p+1) && !isspace(*(p+1))) goto err;
|
456
|
+
done=1;
|
457
|
+
} else if (!*p) {
|
458
|
+
/* unterminated quotes */
|
459
|
+
goto err;
|
460
|
+
} else {
|
461
|
+
current = sdscatlen(current,p,1);
|
462
|
+
}
|
463
|
+
} else {
|
464
|
+
switch(*p) {
|
465
|
+
case ' ':
|
466
|
+
case '\n':
|
467
|
+
case '\r':
|
468
|
+
case '\t':
|
469
|
+
case '\0':
|
470
|
+
done=1;
|
471
|
+
break;
|
472
|
+
case '"':
|
473
|
+
inq=1;
|
474
|
+
break;
|
475
|
+
default:
|
476
|
+
current = sdscatlen(current,p,1);
|
477
|
+
break;
|
478
|
+
}
|
479
|
+
}
|
480
|
+
if (*p) p++;
|
481
|
+
if (current == NULL) goto err;
|
482
|
+
}
|
483
|
+
/* add the token to the vector */
|
484
|
+
_vector = realloc(vector,((*argc)+1)*sizeof(char*));
|
485
|
+
if (_vector == NULL) goto err;
|
486
|
+
|
487
|
+
vector = _vector;
|
488
|
+
vector[*argc] = current;
|
489
|
+
(*argc)++;
|
490
|
+
current = NULL;
|
491
|
+
} else {
|
492
|
+
return vector;
|
493
|
+
}
|
494
|
+
}
|
495
|
+
|
496
|
+
err:
|
497
|
+
while((*argc)--)
|
498
|
+
sdsfree(vector[*argc]);
|
499
|
+
if (vector != NULL) free(vector);
|
500
|
+
if (current != NULL) sdsfree(current);
|
501
|
+
return NULL;
|
502
|
+
}
|
503
|
+
|
504
|
+
#ifdef SDS_TEST_MAIN
|
505
|
+
#include <stdio.h>
|
506
|
+
|
507
|
+
int __failed_tests = 0;
|
508
|
+
int __test_num = 0;
|
509
|
+
#define test_cond(descr,_c) do { \
|
510
|
+
__test_num++; printf("%d - %s: ", __test_num, descr); \
|
511
|
+
if(_c) printf("PASSED\n"); else {printf("FAILED\n"); __failed_tests++;} \
|
512
|
+
} while(0);
|
513
|
+
#define test_report() do { \
|
514
|
+
printf("%d tests, %d passed, %d failed\n", __test_num, \
|
515
|
+
__test_num-__failed_tests, __failed_tests); \
|
516
|
+
if (__failed_tests) { \
|
517
|
+
printf("=== WARNING === We have failed tests here...\n"); \
|
518
|
+
} \
|
519
|
+
} while(0);
|
520
|
+
|
521
|
+
int main(void) {
|
522
|
+
{
|
523
|
+
sds x = sdsnew("foo"), y;
|
524
|
+
|
525
|
+
test_cond("Create a string and obtain the length",
|
526
|
+
sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0)
|
527
|
+
|
528
|
+
sdsfree(x);
|
529
|
+
x = sdsnewlen("foo",2);
|
530
|
+
test_cond("Create a string with specified length",
|
531
|
+
sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0)
|
532
|
+
|
533
|
+
x = sdscat(x,"bar");
|
534
|
+
test_cond("Strings concatenation",
|
535
|
+
sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0);
|
536
|
+
|
537
|
+
x = sdscpy(x,"a");
|
538
|
+
test_cond("sdscpy() against an originally longer string",
|
539
|
+
sdslen(x) == 1 && memcmp(x,"a\0",2) == 0)
|
540
|
+
|
541
|
+
x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk");
|
542
|
+
test_cond("sdscpy() against an originally shorter string",
|
543
|
+
sdslen(x) == 33 &&
|
544
|
+
memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0)
|
545
|
+
|
546
|
+
sdsfree(x);
|
547
|
+
x = sdscatprintf(sdsempty(),"%d",123);
|
548
|
+
test_cond("sdscatprintf() seems working in the base case",
|
549
|
+
sdslen(x) == 3 && memcmp(x,"123\0",4) ==0)
|
550
|
+
|
551
|
+
sdsfree(x);
|
552
|
+
x = sdstrim(sdsnew("xxciaoyyy"),"xy");
|
553
|
+
test_cond("sdstrim() correctly trims characters",
|
554
|
+
sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0)
|
555
|
+
|
556
|
+
y = sdsrange(sdsdup(x),1,1);
|
557
|
+
test_cond("sdsrange(...,1,1)",
|
558
|
+
sdslen(y) == 1 && memcmp(y,"i\0",2) == 0)
|
559
|
+
|
560
|
+
sdsfree(y);
|
561
|
+
y = sdsrange(sdsdup(x),1,-1);
|
562
|
+
test_cond("sdsrange(...,1,-1)",
|
563
|
+
sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
|
564
|
+
|
565
|
+
sdsfree(y);
|
566
|
+
y = sdsrange(sdsdup(x),-2,-1);
|
567
|
+
test_cond("sdsrange(...,-2,-1)",
|
568
|
+
sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0)
|
569
|
+
|
570
|
+
sdsfree(y);
|
571
|
+
y = sdsrange(sdsdup(x),2,1);
|
572
|
+
test_cond("sdsrange(...,2,1)",
|
573
|
+
sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
|
574
|
+
|
575
|
+
sdsfree(y);
|
576
|
+
y = sdsrange(sdsdup(x),1,100);
|
577
|
+
test_cond("sdsrange(...,1,100)",
|
578
|
+
sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
|
579
|
+
|
580
|
+
sdsfree(y);
|
581
|
+
y = sdsrange(sdsdup(x),100,100);
|
582
|
+
test_cond("sdsrange(...,100,100)",
|
583
|
+
sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
|
584
|
+
|
585
|
+
sdsfree(y);
|
586
|
+
sdsfree(x);
|
587
|
+
x = sdsnew("foo");
|
588
|
+
y = sdsnew("foa");
|
589
|
+
test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0)
|
590
|
+
|
591
|
+
sdsfree(y);
|
592
|
+
sdsfree(x);
|
593
|
+
x = sdsnew("bar");
|
594
|
+
y = sdsnew("bar");
|
595
|
+
test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0)
|
596
|
+
|
597
|
+
sdsfree(y);
|
598
|
+
sdsfree(x);
|
599
|
+
x = sdsnew("aar");
|
600
|
+
y = sdsnew("bar");
|
601
|
+
test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0)
|
602
|
+
}
|
603
|
+
test_report()
|
604
|
+
}
|
605
|
+
#endif
|