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