Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 491 lines (434 sloc) 14.056 kb
330c90b fmacros in utils.c to avoid warning about strcasecmp()
antirez authored
1 #include "fmacros.h"
5d08193 @pietern Tests for string2ll; move isObject* to object.c
pietern authored
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
e2641e0 @antirez redis.c split into many different C files.
authored
5 #include <ctype.h>
6 #include <limits.h>
672b0a1 @pietern Fast conversion of double when representable as long long
pietern authored
7 #include <math.h>
44f508f @antirez clusterGetRandomName() generalized into getRandomHexChars() so that we c...
authored
8 #include <unistd.h>
9 #include <sys/time.h>
330c90b fmacros in utils.c to avoid warning about strcasecmp()
antirez authored
10
5d08193 @pietern Tests for string2ll; move isObject* to object.c
pietern authored
11 #include "util.h"
e2641e0 @antirez redis.c split into many different C files.
authored
12
13 /* Glob-style pattern matching. */
14 int stringmatchlen(const char *pattern, int patternLen,
15 const char *string, int stringLen, int nocase)
16 {
17 while(patternLen) {
18 switch(pattern[0]) {
19 case '*':
20 while (pattern[1] == '*') {
21 pattern++;
22 patternLen--;
23 }
24 if (patternLen == 1)
25 return 1; /* match */
26 while(stringLen) {
27 if (stringmatchlen(pattern+1, patternLen-1,
28 string, stringLen, nocase))
29 return 1; /* match */
30 string++;
31 stringLen--;
32 }
33 return 0; /* no match */
34 break;
35 case '?':
36 if (stringLen == 0)
37 return 0; /* no match */
38 string++;
39 stringLen--;
40 break;
41 case '[':
42 {
43 int not, match;
44
45 pattern++;
46 patternLen--;
47 not = pattern[0] == '^';
48 if (not) {
49 pattern++;
50 patternLen--;
51 }
52 match = 0;
53 while(1) {
54 if (pattern[0] == '\\') {
55 pattern++;
56 patternLen--;
57 if (pattern[0] == string[0])
58 match = 1;
59 } else if (pattern[0] == ']') {
60 break;
61 } else if (patternLen == 0) {
62 pattern--;
63 patternLen++;
64 break;
65 } else if (pattern[1] == '-' && patternLen >= 3) {
66 int start = pattern[0];
67 int end = pattern[2];
68 int c = string[0];
69 if (start > end) {
70 int t = start;
71 start = end;
72 end = t;
73 }
74 if (nocase) {
75 start = tolower(start);
76 end = tolower(end);
77 c = tolower(c);
78 }
79 pattern += 2;
80 patternLen -= 2;
81 if (c >= start && c <= end)
82 match = 1;
83 } else {
84 if (!nocase) {
85 if (pattern[0] == string[0])
86 match = 1;
87 } else {
88 if (tolower((int)pattern[0]) == tolower((int)string[0]))
89 match = 1;
90 }
91 }
92 pattern++;
93 patternLen--;
94 }
95 if (not)
96 match = !match;
97 if (!match)
98 return 0; /* no match */
99 string++;
100 stringLen--;
101 break;
102 }
103 case '\\':
104 if (patternLen >= 2) {
105 pattern++;
106 patternLen--;
107 }
108 /* fall through */
109 default:
110 if (!nocase) {
111 if (pattern[0] != string[0])
112 return 0; /* no match */
113 } else {
114 if (tolower((int)pattern[0]) != tolower((int)string[0]))
115 return 0; /* no match */
116 }
117 string++;
118 stringLen--;
119 break;
120 }
121 pattern++;
122 patternLen--;
123 if (stringLen == 0) {
124 while(*pattern == '*') {
125 pattern++;
126 patternLen--;
127 }
128 break;
129 }
130 }
131 if (patternLen == 0 && stringLen == 0)
132 return 1;
133 return 0;
134 }
135
136 int stringmatch(const char *pattern, const char *string, int nocase) {
137 return stringmatchlen(pattern,strlen(pattern),string,strlen(string),nocase);
138 }
139
140 /* Convert a string representing an amount of memory into the number of
141 * bytes, so for instance memtoll("1Gi") will return 1073741824 that is
142 * (1024*1024*1024).
143 *
144 * On parsing error, if *err is not NULL, it's set to 1, otherwise it's
145 * set to 0 */
146 long long memtoll(const char *p, int *err) {
147 const char *u;
148 char buf[128];
149 long mul; /* unit multiplier */
150 long long val;
151 unsigned int digits;
152
153 if (err) *err = 0;
154 /* Search the first non digit character. */
155 u = p;
156 if (*u == '-') u++;
157 while(*u && isdigit(*u)) u++;
158 if (*u == '\0' || !strcasecmp(u,"b")) {
159 mul = 1;
160 } else if (!strcasecmp(u,"k")) {
161 mul = 1000;
162 } else if (!strcasecmp(u,"kb")) {
163 mul = 1024;
164 } else if (!strcasecmp(u,"m")) {
165 mul = 1000*1000;
166 } else if (!strcasecmp(u,"mb")) {
167 mul = 1024*1024;
168 } else if (!strcasecmp(u,"g")) {
169 mul = 1000L*1000*1000;
170 } else if (!strcasecmp(u,"gb")) {
171 mul = 1024L*1024*1024;
172 } else {
173 if (err) *err = 1;
174 mul = 1;
175 }
176 digits = u-p;
177 if (digits >= sizeof(buf)) {
178 if (err) *err = 1;
179 return LLONG_MAX;
180 }
181 memcpy(buf,p,digits);
182 buf[digits] = '\0';
183 val = strtoll(buf,NULL,10);
184 return val*mul;
185 }
186
187 /* Convert a long long into a string. Returns the number of
188 * characters needed to represent the number, that can be shorter if passed
189 * buffer length is not enough to store the whole number. */
190 int ll2string(char *s, size_t len, long long value) {
191 char buf[32], *p;
192 unsigned long long v;
193 size_t l;
194
195 if (len == 0) return 0;
196 v = (value < 0) ? -value : value;
197 p = buf+31; /* point to the last character */
198 do {
199 *p-- = '0'+(v%10);
200 v /= 10;
201 } while(v);
202 if (value < 0) *p-- = '-';
203 p++;
204 l = 32-(p-buf);
205 if (l+1 > len) l = len-1; /* Make sure it fits, including the nul term */
206 memcpy(s,p,l);
207 s[l] = '\0';
208 return l;
209 }
210
d4e07f1 @pietern Add new string to long long function
pietern authored
211 /* Convert a string into a long long. Returns 1 if the string could be parsed
212 * into a (non-overflowing) long long, 0 otherwise. The value will be set to
213 * the parsed value when appropriate. */
214 int string2ll(char *s, size_t slen, long long *value) {
215 char *p = s;
216 size_t plen = 0;
217 int negative = 0;
218 unsigned long long v;
219
220 if (plen == slen)
221 return 0;
222
5d08193 @pietern Tests for string2ll; move isObject* to object.c
pietern authored
223 /* Special case: first and only digit is 0. */
224 if (slen == 1 && p[0] == '0') {
225 if (value != NULL) *value = 0;
226 return 1;
227 }
228
d4e07f1 @pietern Add new string to long long function
pietern authored
229 if (p[0] == '-') {
230 negative = 1;
231 p++; plen++;
232
233 /* Abort on only a negative sign. */
234 if (plen == slen)
235 return 0;
236 }
237
5cbe90d @antirez Fixed a problem with string2ll()
authored
238 /* First digit should be 1-9, otherwise the string should just be 0. */
d4e07f1 @pietern Add new string to long long function
pietern authored
239 if (p[0] >= '1' && p[0] <= '9') {
240 v = p[0]-'0';
241 p++; plen++;
5cbe90d @antirez Fixed a problem with string2ll()
authored
242 } else if (p[0] == '0' && slen == 1) {
243 *value = 0;
244 return 1;
d4e07f1 @pietern Add new string to long long function
pietern authored
245 } else {
246 return 0;
247 }
248
249 while (plen < slen && p[0] >= '0' && p[0] <= '9') {
250 if (v > (ULLONG_MAX / 10)) /* Overflow. */
251 return 0;
252 v *= 10;
253
254 if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */
255 return 0;
256 v += p[0]-'0';
257
258 p++; plen++;
259 }
260
261 /* Return if not all bytes were used. */
262 if (plen < slen)
263 return 0;
264
265 if (negative) {
5d08193 @pietern Tests for string2ll; move isObject* to object.c
pietern authored
266 if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */
d4e07f1 @pietern Add new string to long long function
pietern authored
267 return 0;
268 if (value != NULL) *value = -v;
269 } else {
270 if (v > LLONG_MAX) /* Overflow. */
271 return 0;
272 if (value != NULL) *value = v;
273 }
274 return 1;
275 }
276
5d08193 @pietern Tests for string2ll; move isObject* to object.c
pietern authored
277 /* Convert a string into a long. Returns 1 if the string could be parsed into a
278 * (non-overflowing) long, 0 otherwise. The value will be set to the parsed
279 * value when appropriate. */
280 int string2l(char *s, size_t slen, long *lval) {
281 long long llval;
282
283 if (!string2ll(s,slen,&llval))
284 return 0;
285
286 if (llval < LONG_MIN || llval > LONG_MAX)
287 return 0;
288
289 *lval = (long)llval;
290 return 1;
291 }
292
672b0a1 @pietern Fast conversion of double when representable as long long
pietern authored
293 /* Convert a double to a string representation. Returns the number of bytes
294 * required. The representation should always be parsable by stdtod(3). */
295 int d2string(char *buf, size_t len, double value) {
296 if (isnan(value)) {
297 len = snprintf(buf,len,"nan");
298 } else if (isinf(value)) {
299 if (value < 0)
300 len = snprintf(buf,len,"-inf");
301 else
302 len = snprintf(buf,len,"inf");
303 } else if (value == 0) {
304 /* See: http://en.wikipedia.org/wiki/Signed_zero, "Comparisons". */
305 if (1.0/value < 0)
306 len = snprintf(buf,len,"-0");
307 else
308 len = snprintf(buf,len,"0");
309 } else {
310 #if (DBL_MANT_DIG >= 52) && (LLONG_MAX == 0x7fffffffffffffffLL)
311 /* Check if the float is in a safe range to be casted into a
312 * long long. We are assuming that long long is 64 bit here.
313 * Also we are assuming that there are no implementations around where
314 * double has precision < 52 bit.
315 *
316 * Under this assumptions we test if a double is inside an interval
317 * where casting to long long is safe. Then using two castings we
318 * make sure the decimal part is zero. If all this is true we use
319 * integer printing function that is much faster. */
320 double min = -4503599627370495; /* (2^52)-1 */
321 double max = 4503599627370496; /* -(2^52) */
322 if (val > min && val < max && value == ((double)((long long)value)))
323 len = ll2string(buf,len,(long long)value);
324 else
325 #endif
326 len = snprintf(buf,len,"%.17g",value);
327 }
328
329 return len;
330 }
331
44f508f @antirez clusterGetRandomName() generalized into getRandomHexChars() so that we c...
authored
332 /* Generate the Redis "Run ID", a SHA1-sized random number that identifies a
333 * given execution of Redis, so that if you are talking with an instance
334 * having run_id == A, and you reconnect and it has run_id == B, you can be
335 * sure that it is either a different instance or it was restarted. */
336 void getRandomHexChars(char *p, unsigned int len) {
337 FILE *fp = fopen("/dev/urandom","r");
338 char *charset = "0123456789abcdef";
339 unsigned int j;
340
341 if (fp == NULL || fread(p,len,1,fp) == 0) {
342 /* If we can't read from /dev/urandom, do some reasonable effort
343 * in order to create some entropy, since this function is used to
344 * generate run_id and cluster instance IDs */
345 char *x = p;
346 unsigned int l = len;
347 struct timeval tv;
348 pid_t pid = getpid();
349
350 /* Use time and PID to fill the initial array. */
351 gettimeofday(&tv,NULL);
352 if (l >= sizeof(tv.tv_usec)) {
353 memcpy(x,&tv.tv_usec,sizeof(tv.tv_usec));
354 l -= sizeof(tv.tv_usec);
355 x += sizeof(tv.tv_usec);
356 }
357 if (l >= sizeof(tv.tv_sec)) {
358 memcpy(x,&tv.tv_sec,sizeof(tv.tv_sec));
359 l -= sizeof(tv.tv_sec);
360 x += sizeof(tv.tv_sec);
361 }
362 if (l >= sizeof(pid)) {
363 memcpy(x,&pid,sizeof(pid));
364 l -= sizeof(pid);
365 x += sizeof(pid);
366 }
367 /* Finally xor it with rand() output, that was already seeded with
368 * time() at startup. */
369 for (j = 0; j < len; j++)
370 p[j] ^= rand();
371 }
372 /* Turn it into hex digits taking just 4 bits out of 8 for every byte. */
373 for (j = 0; j < len; j++)
374 p[j] = charset[p[j] & 0x0F];
375 fclose(fp);
376 }
377
5d08193 @pietern Tests for string2ll; move isObject* to object.c
pietern authored
378 #ifdef UTIL_TEST_MAIN
379 #include <assert.h>
380
381 void test_string2ll(void) {
382 char buf[32];
383 long long v;
384
385 /* May not start with +. */
386 strcpy(buf,"+1");
387 assert(string2ll(buf,strlen(buf),&v) == 0);
388
3edbcab @pietern Extra tests for string2ll
pietern authored
389 /* Leading space. */
390 strcpy(buf," 1");
391 assert(string2ll(buf,strlen(buf),&v) == 0);
392
393 /* Trailing space. */
394 strcpy(buf,"1 ");
395 assert(string2ll(buf,strlen(buf),&v) == 0);
396
5d08193 @pietern Tests for string2ll; move isObject* to object.c
pietern authored
397 /* May not start with 0. */
398 strcpy(buf,"01");
399 assert(string2ll(buf,strlen(buf),&v) == 0);
400
401 strcpy(buf,"-1");
402 assert(string2ll(buf,strlen(buf),&v) == 1);
403 assert(v == -1);
404
405 strcpy(buf,"0");
406 assert(string2ll(buf,strlen(buf),&v) == 1);
407 assert(v == 0);
408
409 strcpy(buf,"1");
410 assert(string2ll(buf,strlen(buf),&v) == 1);
411 assert(v == 1);
412
413 strcpy(buf,"99");
414 assert(string2ll(buf,strlen(buf),&v) == 1);
415 assert(v == 99);
416
417 strcpy(buf,"-99");
418 assert(string2ll(buf,strlen(buf),&v) == 1);
419 assert(v == -99);
420
421 strcpy(buf,"-9223372036854775808");
422 assert(string2ll(buf,strlen(buf),&v) == 1);
423 assert(v == LLONG_MIN);
424
425 strcpy(buf,"-9223372036854775809"); /* overflow */
426 assert(string2ll(buf,strlen(buf),&v) == 0);
427
428 strcpy(buf,"9223372036854775807");
429 assert(string2ll(buf,strlen(buf),&v) == 1);
430 assert(v == LLONG_MAX);
431
432 strcpy(buf,"9223372036854775808"); /* overflow */
433 assert(string2ll(buf,strlen(buf),&v) == 0);
ec7e138 @antirez test for intset integer encodability test and some small refactoring
authored
434 }
435
5d08193 @pietern Tests for string2ll; move isObject* to object.c
pietern authored
436 void test_string2l(void) {
437 char buf[32];
438 long v;
439
440 /* May not start with +. */
441 strcpy(buf,"+1");
442 assert(string2l(buf,strlen(buf),&v) == 0);
443
444 /* May not start with 0. */
445 strcpy(buf,"01");
446 assert(string2l(buf,strlen(buf),&v) == 0);
447
448 strcpy(buf,"-1");
449 assert(string2l(buf,strlen(buf),&v) == 1);
450 assert(v == -1);
451
452 strcpy(buf,"0");
453 assert(string2l(buf,strlen(buf),&v) == 1);
454 assert(v == 0);
455
456 strcpy(buf,"1");
457 assert(string2l(buf,strlen(buf),&v) == 1);
458 assert(v == 1);
459
460 strcpy(buf,"99");
461 assert(string2l(buf,strlen(buf),&v) == 1);
462 assert(v == 99);
ec7e138 @antirez test for intset integer encodability test and some small refactoring
authored
463
5d08193 @pietern Tests for string2ll; move isObject* to object.c
pietern authored
464 strcpy(buf,"-99");
465 assert(string2l(buf,strlen(buf),&v) == 1);
466 assert(v == -99);
467
468 #if LONG_MAX != LLONG_MAX
469 strcpy(buf,"-2147483648");
470 assert(string2l(buf,strlen(buf),&v) == 1);
471 assert(v == LONG_MIN);
472
473 strcpy(buf,"-2147483649"); /* overflow */
474 assert(string2l(buf,strlen(buf),&v) == 0);
475
476 strcpy(buf,"2147483647");
477 assert(string2l(buf,strlen(buf),&v) == 1);
478 assert(v == LONG_MAX);
479
480 strcpy(buf,"2147483648"); /* overflow */
481 assert(string2l(buf,strlen(buf),&v) == 0);
482 #endif
e2641e0 @antirez redis.c split into many different C files.
authored
483 }
ec7e138 @antirez test for intset integer encodability test and some small refactoring
authored
484
5d08193 @pietern Tests for string2ll; move isObject* to object.c
pietern authored
485 int main(int argc, char **argv) {
486 test_string2ll();
487 test_string2l();
488 return 0;
ec7e138 @antirez test for intset integer encodability test and some small refactoring
authored
489 }
5d08193 @pietern Tests for string2ll; move isObject* to object.c
pietern authored
490 #endif
Something went wrong with that request. Please try again.