Skip to content
This repository
Newer
Older
100644 490 lines (434 sloc) 14.056 kb
330c90b0 » antirez
2011-05-16 fmacros in utils.c to avoid warning about strcasecmp()
1 #include "fmacros.h"
5d081931 » pietern
2011-04-27 Tests for string2ll; move isObject* to object.c
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
e2641e09 »
2010-06-22 redis.c split into many different C files.
5 #include <ctype.h>
6 #include <limits.h>
672b0a1b » pietern
2011-03-08 Fast conversion of double when representable as long long
7 #include <math.h>
44f508f1 »
2012-03-08 clusterGetRandomName() generalized into getRandomHexChars() so that w…
8 #include <unistd.h>
9 #include <sys/time.h>
330c90b0 » antirez
2011-05-16 fmacros in utils.c to avoid warning about strcasecmp()
10
5d081931 » pietern
2011-04-27 Tests for string2ll; move isObject* to object.c
11 #include "util.h"
e2641e09 »
2010-06-22 redis.c split into many different C files.
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
d4e07f17 » pietern
2011-03-10 Add new string to long long function
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
5d081931 » pietern
2011-04-27 Tests for string2ll; move isObject* to object.c
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
d4e07f17 » pietern
2011-03-10 Add new string to long long function
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
5cbe90db »
2011-05-01 Fixed a problem with string2ll()
238 /* First digit should be 1-9, otherwise the string should just be 0. */
d4e07f17 » pietern
2011-03-10 Add new string to long long function
239 if (p[0] >= '1' && p[0] <= '9') {
240 v = p[0]-'0';
241 p++; plen++;
5cbe90db »
2011-05-01 Fixed a problem with string2ll()
242 } else if (p[0] == '0' && slen == 1) {
243 *value = 0;
244 return 1;
d4e07f17 » pietern
2011-03-10 Add new string to long long function
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) {
5d081931 » pietern
2011-04-27 Tests for string2ll; move isObject* to object.c
266 if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */
d4e07f17 » pietern
2011-03-10 Add new string to long long function
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
5d081931 » pietern
2011-04-27 Tests for string2ll; move isObject* to object.c
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
672b0a1b » pietern
2011-03-08 Fast conversion of double when representable as long long
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
44f508f1 »
2012-03-08 clusterGetRandomName() generalized into getRandomHexChars() so that w…
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
5d081931 » pietern
2011-04-27 Tests for string2ll; move isObject* to object.c
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
3edbcab9 » pietern
2011-04-27 Extra tests for string2ll
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
5d081931 » pietern
2011-04-27 Tests for string2ll; move isObject* to object.c
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);
ec7e1389 »
2010-08-26 test for intset integer encodability test and some small refactoring
434 }
435
5d081931 » pietern
2011-04-27 Tests for string2ll; move isObject* to object.c
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);
ec7e1389 »
2010-08-26 test for intset integer encodability test and some small refactoring
463
5d081931 » pietern
2011-04-27 Tests for string2ll; move isObject* to object.c
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
e2641e09 »
2010-06-22 redis.c split into many different C files.
483 }
ec7e1389 »
2010-08-26 test for intset integer encodability test and some small refactoring
484
5d081931 » pietern
2011-04-27 Tests for string2ll; move isObject* to object.c
485 int main(int argc, char **argv) {
486 test_string2ll();
487 test_string2l();
488 return 0;
ec7e1389 »
2010-08-26 test for intset integer encodability test and some small refactoring
489 }
5d081931 » pietern
2011-04-27 Tests for string2ll; move isObject* to object.c
490 #endif
Something went wrong with that request. Please try again.