xref: /redis-3.2.3/src/util.c (revision 4942145d)
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 
203 /* Check if the sds string 's' can be represented by a long long
204  * (that is, is a number that fits into long without any other space or
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).
207  *
208  * If so, the function returns REDIS_OK and *llongval is set to the value
209  * of the number. Otherwise REDIS_ERR is returned */
210 int isStringRepresentableAsLongLong(sds s, long long *llongval) {
211     char buf[32], *endptr;
212     long long value;
213     int slen;
214 
215     value = strtoll(s, &endptr, 10);
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;
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;
232     return REDIS_OK;
233 }
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 }
244