mirror of
https://github.com/fluencelabs/redis
synced 2025-06-18 19:51:22 +00:00
redis.c split into many different C files.
networking related stuff moved into networking.c moved more code more work on layout of source code SDS instantaneuos memory saving. By Pieter and Salvatore at VMware ;) cleanly compiling again after the first split, now splitting it in more C files moving more things around... work in progress split replication code splitting more Sets split Hash split replication split even more splitting more splitting minor change
This commit is contained in:
223
src/util.c
Normal file
223
src/util.c
Normal file
@ -0,0 +1,223 @@
|
||||
#include "redis.h"
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* Glob-style pattern matching. */
|
||||
int stringmatchlen(const char *pattern, int patternLen,
|
||||
const char *string, int stringLen, int nocase)
|
||||
{
|
||||
while(patternLen) {
|
||||
switch(pattern[0]) {
|
||||
case '*':
|
||||
while (pattern[1] == '*') {
|
||||
pattern++;
|
||||
patternLen--;
|
||||
}
|
||||
if (patternLen == 1)
|
||||
return 1; /* match */
|
||||
while(stringLen) {
|
||||
if (stringmatchlen(pattern+1, patternLen-1,
|
||||
string, stringLen, nocase))
|
||||
return 1; /* match */
|
||||
string++;
|
||||
stringLen--;
|
||||
}
|
||||
return 0; /* no match */
|
||||
break;
|
||||
case '?':
|
||||
if (stringLen == 0)
|
||||
return 0; /* no match */
|
||||
string++;
|
||||
stringLen--;
|
||||
break;
|
||||
case '[':
|
||||
{
|
||||
int not, match;
|
||||
|
||||
pattern++;
|
||||
patternLen--;
|
||||
not = pattern[0] == '^';
|
||||
if (not) {
|
||||
pattern++;
|
||||
patternLen--;
|
||||
}
|
||||
match = 0;
|
||||
while(1) {
|
||||
if (pattern[0] == '\\') {
|
||||
pattern++;
|
||||
patternLen--;
|
||||
if (pattern[0] == string[0])
|
||||
match = 1;
|
||||
} else if (pattern[0] == ']') {
|
||||
break;
|
||||
} else if (patternLen == 0) {
|
||||
pattern--;
|
||||
patternLen++;
|
||||
break;
|
||||
} else if (pattern[1] == '-' && patternLen >= 3) {
|
||||
int start = pattern[0];
|
||||
int end = pattern[2];
|
||||
int c = string[0];
|
||||
if (start > end) {
|
||||
int t = start;
|
||||
start = end;
|
||||
end = t;
|
||||
}
|
||||
if (nocase) {
|
||||
start = tolower(start);
|
||||
end = tolower(end);
|
||||
c = tolower(c);
|
||||
}
|
||||
pattern += 2;
|
||||
patternLen -= 2;
|
||||
if (c >= start && c <= end)
|
||||
match = 1;
|
||||
} else {
|
||||
if (!nocase) {
|
||||
if (pattern[0] == string[0])
|
||||
match = 1;
|
||||
} else {
|
||||
if (tolower((int)pattern[0]) == tolower((int)string[0]))
|
||||
match = 1;
|
||||
}
|
||||
}
|
||||
pattern++;
|
||||
patternLen--;
|
||||
}
|
||||
if (not)
|
||||
match = !match;
|
||||
if (!match)
|
||||
return 0; /* no match */
|
||||
string++;
|
||||
stringLen--;
|
||||
break;
|
||||
}
|
||||
case '\\':
|
||||
if (patternLen >= 2) {
|
||||
pattern++;
|
||||
patternLen--;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
if (!nocase) {
|
||||
if (pattern[0] != string[0])
|
||||
return 0; /* no match */
|
||||
} else {
|
||||
if (tolower((int)pattern[0]) != tolower((int)string[0]))
|
||||
return 0; /* no match */
|
||||
}
|
||||
string++;
|
||||
stringLen--;
|
||||
break;
|
||||
}
|
||||
pattern++;
|
||||
patternLen--;
|
||||
if (stringLen == 0) {
|
||||
while(*pattern == '*') {
|
||||
pattern++;
|
||||
patternLen--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (patternLen == 0 && stringLen == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stringmatch(const char *pattern, const char *string, int nocase) {
|
||||
return stringmatchlen(pattern,strlen(pattern),string,strlen(string),nocase);
|
||||
}
|
||||
|
||||
/* Convert a string representing an amount of memory into the number of
|
||||
* bytes, so for instance memtoll("1Gi") will return 1073741824 that is
|
||||
* (1024*1024*1024).
|
||||
*
|
||||
* On parsing error, if *err is not NULL, it's set to 1, otherwise it's
|
||||
* set to 0 */
|
||||
long long memtoll(const char *p, int *err) {
|
||||
const char *u;
|
||||
char buf[128];
|
||||
long mul; /* unit multiplier */
|
||||
long long val;
|
||||
unsigned int digits;
|
||||
|
||||
if (err) *err = 0;
|
||||
/* Search the first non digit character. */
|
||||
u = p;
|
||||
if (*u == '-') u++;
|
||||
while(*u && isdigit(*u)) u++;
|
||||
if (*u == '\0' || !strcasecmp(u,"b")) {
|
||||
mul = 1;
|
||||
} else if (!strcasecmp(u,"k")) {
|
||||
mul = 1000;
|
||||
} else if (!strcasecmp(u,"kb")) {
|
||||
mul = 1024;
|
||||
} else if (!strcasecmp(u,"m")) {
|
||||
mul = 1000*1000;
|
||||
} else if (!strcasecmp(u,"mb")) {
|
||||
mul = 1024*1024;
|
||||
} else if (!strcasecmp(u,"g")) {
|
||||
mul = 1000L*1000*1000;
|
||||
} else if (!strcasecmp(u,"gb")) {
|
||||
mul = 1024L*1024*1024;
|
||||
} else {
|
||||
if (err) *err = 1;
|
||||
mul = 1;
|
||||
}
|
||||
digits = u-p;
|
||||
if (digits >= sizeof(buf)) {
|
||||
if (err) *err = 1;
|
||||
return LLONG_MAX;
|
||||
}
|
||||
memcpy(buf,p,digits);
|
||||
buf[digits] = '\0';
|
||||
val = strtoll(buf,NULL,10);
|
||||
return val*mul;
|
||||
}
|
||||
|
||||
/* Convert a long long into a string. Returns the number of
|
||||
* characters needed to represent the number, that can be shorter if passed
|
||||
* buffer length is not enough to store the whole number. */
|
||||
int ll2string(char *s, size_t len, long long value) {
|
||||
char buf[32], *p;
|
||||
unsigned long long v;
|
||||
size_t l;
|
||||
|
||||
if (len == 0) return 0;
|
||||
v = (value < 0) ? -value : value;
|
||||
p = buf+31; /* point to the last character */
|
||||
do {
|
||||
*p-- = '0'+(v%10);
|
||||
v /= 10;
|
||||
} while(v);
|
||||
if (value < 0) *p-- = '-';
|
||||
p++;
|
||||
l = 32-(p-buf);
|
||||
if (l+1 > len) l = len-1; /* Make sure it fits, including the nul term */
|
||||
memcpy(s,p,l);
|
||||
s[l] = '\0';
|
||||
return l;
|
||||
}
|
||||
|
||||
/* Check if the nul-terminated string 's' can be represented by a long
|
||||
* (that is, is a number that fits into long without any other space or
|
||||
* character before or after the digits).
|
||||
*
|
||||
* If so, the function returns REDIS_OK and *longval is set to the value
|
||||
* of the number. Otherwise REDIS_ERR is returned */
|
||||
int isStringRepresentableAsLong(sds s, long *longval) {
|
||||
char buf[32], *endptr;
|
||||
long value;
|
||||
int slen;
|
||||
|
||||
value = strtol(s, &endptr, 10);
|
||||
if (endptr[0] != '\0') return REDIS_ERR;
|
||||
slen = ll2string(buf,32,value);
|
||||
|
||||
/* If the number converted back into a string is not identical
|
||||
* then it's not possible to encode the string as integer */
|
||||
if (sdslen(s) != (unsigned)slen || memcmp(buf,s,slen)) return REDIS_ERR;
|
||||
if (longval) *longval = value;
|
||||
return REDIS_OK;
|
||||
}
|
Reference in New Issue
Block a user