]>
git.saurik.com Git - redis.git/blob - src/util.c
2 * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Redis nor the names of its contributors may be used
14 * to endorse or promote products derived from this software without
15 * specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
43 /* Glob-style pattern matching. */
44 int stringmatchlen(const char *pattern
, int patternLen
,
45 const char *string
, int stringLen
, int nocase
)
50 while (pattern
[1] == '*') {
57 if (stringmatchlen(pattern
+1, patternLen
-1,
58 string
, stringLen
, nocase
))
63 return 0; /* no match */
67 return 0; /* no match */
77 not = pattern
[0] == '^';
84 if (pattern
[0] == '\\') {
87 if (pattern
[0] == string
[0])
89 } else if (pattern
[0] == ']') {
91 } else if (patternLen
== 0) {
95 } else if (pattern
[1] == '-' && patternLen
>= 3) {
96 int start
= pattern
[0];
105 start
= tolower(start
);
111 if (c
>= start
&& c
<= end
)
115 if (pattern
[0] == string
[0])
118 if (tolower((int)pattern
[0]) == tolower((int)string
[0]))
128 return 0; /* no match */
134 if (patternLen
>= 2) {
141 if (pattern
[0] != string
[0])
142 return 0; /* no match */
144 if (tolower((int)pattern
[0]) != tolower((int)string
[0]))
145 return 0; /* no match */
153 if (stringLen
== 0) {
154 while(*pattern
== '*') {
161 if (patternLen
== 0 && stringLen
== 0)
166 int stringmatch(const char *pattern
, const char *string
, int nocase
) {
167 return stringmatchlen(pattern
,strlen(pattern
),string
,strlen(string
),nocase
);
170 /* Convert a string representing an amount of memory into the number of
171 * bytes, so for instance memtoll("1Gi") will return 1073741824 that is
174 * On parsing error, if *err is not NULL, it's set to 1, otherwise it's
176 long long memtoll(const char *p
, int *err
) {
179 long mul
; /* unit multiplier */
184 /* Search the first non digit character. */
187 while(*u
&& isdigit(*u
)) u
++;
188 if (*u
== '\0' || !strcasecmp(u
,"b")) {
190 } else if (!strcasecmp(u
,"k")) {
192 } else if (!strcasecmp(u
,"kb")) {
194 } else if (!strcasecmp(u
,"m")) {
196 } else if (!strcasecmp(u
,"mb")) {
198 } else if (!strcasecmp(u
,"g")) {
199 mul
= 1000L*1000*1000;
200 } else if (!strcasecmp(u
,"gb")) {
201 mul
= 1024L*1024*1024;
207 if (digits
>= sizeof(buf
)) {
211 memcpy(buf
,p
,digits
);
213 val
= strtoll(buf
,NULL
,10);
217 /* Convert a long long into a string. Returns the number of
218 * characters needed to represent the number, that can be shorter if passed
219 * buffer length is not enough to store the whole number. */
220 int ll2string(char *s
, size_t len
, long long value
) {
222 unsigned long long v
;
225 if (len
== 0) return 0;
226 v
= (value
< 0) ? -value
: value
;
227 p
= buf
+31; /* point to the last character */
232 if (value
< 0) *p
-- = '-';
235 if (l
+1 > len
) l
= len
-1; /* Make sure it fits, including the nul term */
241 /* Convert a string into a long long. Returns 1 if the string could be parsed
242 * into a (non-overflowing) long long, 0 otherwise. The value will be set to
243 * the parsed value when appropriate. */
244 int string2ll(const char *s
, size_t slen
, long long *value
) {
248 unsigned long long v
;
253 /* Special case: first and only digit is 0. */
254 if (slen
== 1 && p
[0] == '0') {
255 if (value
!= NULL
) *value
= 0;
263 /* Abort on only a negative sign. */
268 /* First digit should be 1-9, otherwise the string should just be 0. */
269 if (p
[0] >= '1' && p
[0] <= '9') {
272 } else if (p
[0] == '0' && slen
== 1) {
279 while (plen
< slen
&& p
[0] >= '0' && p
[0] <= '9') {
280 if (v
> (ULLONG_MAX
/ 10)) /* Overflow. */
284 if (v
> (ULLONG_MAX
- (p
[0]-'0'))) /* Overflow. */
291 /* Return if not all bytes were used. */
296 if (v
> ((unsigned long long)(-(LLONG_MIN
+1))+1)) /* Overflow. */
298 if (value
!= NULL
) *value
= -v
;
300 if (v
> LLONG_MAX
) /* Overflow. */
302 if (value
!= NULL
) *value
= v
;
307 /* Convert a string into a long. Returns 1 if the string could be parsed into a
308 * (non-overflowing) long, 0 otherwise. The value will be set to the parsed
309 * value when appropriate. */
310 int string2l(const char *s
, size_t slen
, long *lval
) {
313 if (!string2ll(s
,slen
,&llval
))
316 if (llval
< LONG_MIN
|| llval
> LONG_MAX
)
323 /* Convert a double to a string representation. Returns the number of bytes
324 * required. The representation should always be parsable by stdtod(3). */
325 int d2string(char *buf
, size_t len
, double value
) {
327 len
= snprintf(buf
,len
,"nan");
328 } else if (isinf(value
)) {
330 len
= snprintf(buf
,len
,"-inf");
332 len
= snprintf(buf
,len
,"inf");
333 } else if (value
== 0) {
334 /* See: http://en.wikipedia.org/wiki/Signed_zero, "Comparisons". */
336 len
= snprintf(buf
,len
,"-0");
338 len
= snprintf(buf
,len
,"0");
340 #if (DBL_MANT_DIG >= 52) && (LLONG_MAX == 0x7fffffffffffffffLL)
341 /* Check if the float is in a safe range to be casted into a
342 * long long. We are assuming that long long is 64 bit here.
343 * Also we are assuming that there are no implementations around where
344 * double has precision < 52 bit.
346 * Under this assumptions we test if a double is inside an interval
347 * where casting to long long is safe. Then using two castings we
348 * make sure the decimal part is zero. If all this is true we use
349 * integer printing function that is much faster. */
350 double min
= -4503599627370495; /* (2^52)-1 */
351 double max
= 4503599627370496; /* -(2^52) */
352 if (value
> min
&& value
< max
&& value
== ((double)((long long)value
)))
353 len
= ll2string(buf
,len
,(long long)value
);
356 len
= snprintf(buf
,len
,"%.17g",value
);
362 /* Generate the Redis "Run ID", a SHA1-sized random number that identifies a
363 * given execution of Redis, so that if you are talking with an instance
364 * having run_id == A, and you reconnect and it has run_id == B, you can be
365 * sure that it is either a different instance or it was restarted. */
366 void getRandomHexChars(char *p
, unsigned int len
) {
367 FILE *fp
= fopen("/dev/urandom","r");
368 char *charset
= "0123456789abcdef";
371 if (fp
== NULL
|| fread(p
,len
,1,fp
) == 0) {
372 /* If we can't read from /dev/urandom, do some reasonable effort
373 * in order to create some entropy, since this function is used to
374 * generate run_id and cluster instance IDs */
376 unsigned int l
= len
;
378 pid_t pid
= getpid();
380 /* Use time and PID to fill the initial array. */
381 gettimeofday(&tv
,NULL
);
382 if (l
>= sizeof(tv
.tv_usec
)) {
383 memcpy(x
,&tv
.tv_usec
,sizeof(tv
.tv_usec
));
384 l
-= sizeof(tv
.tv_usec
);
385 x
+= sizeof(tv
.tv_usec
);
387 if (l
>= sizeof(tv
.tv_sec
)) {
388 memcpy(x
,&tv
.tv_sec
,sizeof(tv
.tv_sec
));
389 l
-= sizeof(tv
.tv_sec
);
390 x
+= sizeof(tv
.tv_sec
);
392 if (l
>= sizeof(pid
)) {
393 memcpy(x
,&pid
,sizeof(pid
));
397 /* Finally xor it with rand() output, that was already seeded with
398 * time() at startup. */
399 for (j
= 0; j
< len
; j
++)
402 /* Turn it into hex digits taking just 4 bits out of 8 for every byte. */
403 for (j
= 0; j
< len
; j
++)
404 p
[j
] = charset
[p
[j
] & 0x0F];
408 #ifdef UTIL_TEST_MAIN
411 void test_string2ll(void) {
415 /* May not start with +. */
417 assert(string2ll(buf
,strlen(buf
),&v
) == 0);
421 assert(string2ll(buf
,strlen(buf
),&v
) == 0);
423 /* Trailing space. */
425 assert(string2ll(buf
,strlen(buf
),&v
) == 0);
427 /* May not start with 0. */
429 assert(string2ll(buf
,strlen(buf
),&v
) == 0);
432 assert(string2ll(buf
,strlen(buf
),&v
) == 1);
436 assert(string2ll(buf
,strlen(buf
),&v
) == 1);
440 assert(string2ll(buf
,strlen(buf
),&v
) == 1);
444 assert(string2ll(buf
,strlen(buf
),&v
) == 1);
448 assert(string2ll(buf
,strlen(buf
),&v
) == 1);
451 strcpy(buf
,"-9223372036854775808");
452 assert(string2ll(buf
,strlen(buf
),&v
) == 1);
453 assert(v
== LLONG_MIN
);
455 strcpy(buf
,"-9223372036854775809"); /* overflow */
456 assert(string2ll(buf
,strlen(buf
),&v
) == 0);
458 strcpy(buf
,"9223372036854775807");
459 assert(string2ll(buf
,strlen(buf
),&v
) == 1);
460 assert(v
== LLONG_MAX
);
462 strcpy(buf
,"9223372036854775808"); /* overflow */
463 assert(string2ll(buf
,strlen(buf
),&v
) == 0);
466 void test_string2l(void) {
470 /* May not start with +. */
472 assert(string2l(buf
,strlen(buf
),&v
) == 0);
474 /* May not start with 0. */
476 assert(string2l(buf
,strlen(buf
),&v
) == 0);
479 assert(string2l(buf
,strlen(buf
),&v
) == 1);
483 assert(string2l(buf
,strlen(buf
),&v
) == 1);
487 assert(string2l(buf
,strlen(buf
),&v
) == 1);
491 assert(string2l(buf
,strlen(buf
),&v
) == 1);
495 assert(string2l(buf
,strlen(buf
),&v
) == 1);
498 #if LONG_MAX != LLONG_MAX
499 strcpy(buf
,"-2147483648");
500 assert(string2l(buf
,strlen(buf
),&v
) == 1);
501 assert(v
== LONG_MIN
);
503 strcpy(buf
,"-2147483649"); /* overflow */
504 assert(string2l(buf
,strlen(buf
),&v
) == 0);
506 strcpy(buf
,"2147483647");
507 assert(string2l(buf
,strlen(buf
),&v
) == 1);
508 assert(v
== LONG_MAX
);
510 strcpy(buf
,"2147483648"); /* overflow */
511 assert(string2l(buf
,strlen(buf
),&v
) == 0);
515 int main(int argc
, char **argv
) {