e2641e09 |
1 | #include "redis.h" |
2 | #include <ctype.h> |
3 | #include <limits.h> |
4 | |
5 | /* Glob-style pattern matching. */ |
6 | int 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 | |
128 | int 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 */ |
138 | long 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. */ |
182 | int 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 |
210 | int 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 | |
226 | int 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 | |
235 | int 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 | } |