]> git.saurik.com Git - redis.git/blame - src/util.c
brainstorming with myself in dscache.c comments
[redis.git] / src / util.c
CommitLineData
e2641e09 1#include "redis.h"
2#include <ctype.h>
3#include <limits.h>
4
5/* Glob-style pattern matching. */
6int stringmatchlen(const char *pattern, int patternLen,
7 const char *string, int stringLen, int nocase)
8{
9 while(patternLen) {
10 switch(pattern[0]) {
11 case '*':
12 while (pattern[1] == '*') {
13 pattern++;
14 patternLen--;
15 }
16 if (patternLen == 1)
17 return 1; /* match */
18 while(stringLen) {
19 if (stringmatchlen(pattern+1, patternLen-1,
20 string, stringLen, nocase))
21 return 1; /* match */
22 string++;
23 stringLen--;
24 }
25 return 0; /* no match */
26 break;
27 case '?':
28 if (stringLen == 0)
29 return 0; /* no match */
30 string++;
31 stringLen--;
32 break;
33 case '[':
34 {
35 int not, match;
36
37 pattern++;
38 patternLen--;
39 not = pattern[0] == '^';
40 if (not) {
41 pattern++;
42 patternLen--;
43 }
44 match = 0;
45 while(1) {
46 if (pattern[0] == '\\') {
47 pattern++;
48 patternLen--;
49 if (pattern[0] == string[0])
50 match = 1;
51 } else if (pattern[0] == ']') {
52 break;
53 } else if (patternLen == 0) {
54 pattern--;
55 patternLen++;
56 break;
57 } else if (pattern[1] == '-' && patternLen >= 3) {
58 int start = pattern[0];
59 int end = pattern[2];
60 int c = string[0];
61 if (start > end) {
62 int t = start;
63 start = end;
64 end = t;
65 }
66 if (nocase) {
67 start = tolower(start);
68 end = tolower(end);
69 c = tolower(c);
70 }
71 pattern += 2;
72 patternLen -= 2;
73 if (c >= start && c <= end)
74 match = 1;
75 } else {
76 if (!nocase) {
77 if (pattern[0] == string[0])
78 match = 1;
79 } else {
80 if (tolower((int)pattern[0]) == tolower((int)string[0]))
81 match = 1;
82 }
83 }
84 pattern++;
85 patternLen--;
86 }
87 if (not)
88 match = !match;
89 if (!match)
90 return 0; /* no match */
91 string++;
92 stringLen--;
93 break;
94 }
95 case '\\':
96 if (patternLen >= 2) {
97 pattern++;
98 patternLen--;
99 }
100 /* fall through */
101 default:
102 if (!nocase) {
103 if (pattern[0] != string[0])
104 return 0; /* no match */
105 } else {
106 if (tolower((int)pattern[0]) != tolower((int)string[0]))
107 return 0; /* no match */
108 }
109 string++;
110 stringLen--;
111 break;
112 }
113 pattern++;
114 patternLen--;
115 if (stringLen == 0) {
116 while(*pattern == '*') {
117 pattern++;
118 patternLen--;
119 }
120 break;
121 }
122 }
123 if (patternLen == 0 && stringLen == 0)
124 return 1;
125 return 0;
126}
127
128int stringmatch(const char *pattern, const char *string, int nocase) {
129 return stringmatchlen(pattern,strlen(pattern),string,strlen(string),nocase);
130}
131
132/* Convert a string representing an amount of memory into the number of
133 * bytes, so for instance memtoll("1Gi") will return 1073741824 that is
134 * (1024*1024*1024).
135 *
136 * On parsing error, if *err is not NULL, it's set to 1, otherwise it's
137 * set to 0 */
138long long memtoll(const char *p, int *err) {
139 const char *u;
140 char buf[128];
141 long mul; /* unit multiplier */
142 long long val;
143 unsigned int digits;
144
145 if (err) *err = 0;
146 /* Search the first non digit character. */
147 u = p;
148 if (*u == '-') u++;
149 while(*u && isdigit(*u)) u++;
150 if (*u == '\0' || !strcasecmp(u,"b")) {
151 mul = 1;
152 } else if (!strcasecmp(u,"k")) {
153 mul = 1000;
154 } else if (!strcasecmp(u,"kb")) {
155 mul = 1024;
156 } else if (!strcasecmp(u,"m")) {
157 mul = 1000*1000;
158 } else if (!strcasecmp(u,"mb")) {
159 mul = 1024*1024;
160 } else if (!strcasecmp(u,"g")) {
161 mul = 1000L*1000*1000;
162 } else if (!strcasecmp(u,"gb")) {
163 mul = 1024L*1024*1024;
164 } else {
165 if (err) *err = 1;
166 mul = 1;
167 }
168 digits = u-p;
169 if (digits >= sizeof(buf)) {
170 if (err) *err = 1;
171 return LLONG_MAX;
172 }
173 memcpy(buf,p,digits);
174 buf[digits] = '\0';
175 val = strtoll(buf,NULL,10);
176 return val*mul;
177}
178
179/* Convert a long long into a string. Returns the number of
180 * characters needed to represent the number, that can be shorter if passed
181 * buffer length is not enough to store the whole number. */
182int ll2string(char *s, size_t len, long long value) {
183 char buf[32], *p;
184 unsigned long long v;
185 size_t l;
186
187 if (len == 0) return 0;
188 v = (value < 0) ? -value : value;
189 p = buf+31; /* point to the last character */
190 do {
191 *p-- = '0'+(v%10);
192 v /= 10;
193 } while(v);
194 if (value < 0) *p-- = '-';
195 p++;
196 l = 32-(p-buf);
197 if (l+1 > len) l = len-1; /* Make sure it fits, including the nul term */
198 memcpy(s,p,l);
199 s[l] = '\0';
200 return l;
201}
202
ec7e1389 203/* Check if the sds string 's' can be represented by a long long
e2641e09 204 * (that is, is a number that fits into long without any other space or
ec7e1389 205 * character before or after the digits, so that converting this number
206 * back to a string will result in the same bytes as the original string).
e2641e09 207 *
ec7e1389 208 * If so, the function returns REDIS_OK and *llongval is set to the value
e2641e09 209 * of the number. Otherwise REDIS_ERR is returned */
ec7e1389 210int isStringRepresentableAsLongLong(sds s, long long *llongval) {
e2641e09 211 char buf[32], *endptr;
ec7e1389 212 long long value;
e2641e09 213 int slen;
214
ec7e1389 215 value = strtoll(s, &endptr, 10);
e2641e09 216 if (endptr[0] != '\0') return REDIS_ERR;
217 slen = ll2string(buf,32,value);
218
219 /* If the number converted back into a string is not identical
220 * then it's not possible to encode the string as integer */
221 if (sdslen(s) != (unsigned)slen || memcmp(buf,s,slen)) return REDIS_ERR;
ec7e1389 222 if (llongval) *llongval = value;
223 return REDIS_OK;
224}
225
226int isStringRepresentableAsLong(sds s, long *longval) {
227 long long ll;
228
229 if (isStringRepresentableAsLongLong(s,&ll) == REDIS_ERR) return REDIS_ERR;
230 if (ll < LONG_MIN || ll > LONG_MAX) return REDIS_ERR;
231 *longval = (long)ll;
e2641e09 232 return REDIS_OK;
233}
ec7e1389 234
235int isObjectRepresentableAsLongLong(robj *o, long long *llongval) {
236 redisAssert(o->type == REDIS_STRING);
237 if (o->encoding == REDIS_ENCODING_INT) {
238 if (llongval) *llongval = (long) o->ptr;
239 return REDIS_OK;
240 } else {
241 return isStringRepresentableAsLongLong(o->ptr,llongval);
242 }
243}