]> git.saurik.com Git - redis.git/blame - src/util.c
AOF auto rewrite percentage option parsing fixed
[redis.git] / src / util.c
CommitLineData
330c90b0 1#include "fmacros.h"
5d081931
PN
2#include <stdlib.h>
3#include <stdio.h>
4#include <string.h>
e2641e09 5#include <ctype.h>
6#include <limits.h>
672b0a1b 7#include <math.h>
330c90b0 8
5d081931 9#include "util.h"
e2641e09 10
11/* Glob-style pattern matching. */
12int stringmatchlen(const char *pattern, int patternLen,
13 const char *string, int stringLen, int nocase)
14{
15 while(patternLen) {
16 switch(pattern[0]) {
17 case '*':
18 while (pattern[1] == '*') {
19 pattern++;
20 patternLen--;
21 }
22 if (patternLen == 1)
23 return 1; /* match */
24 while(stringLen) {
25 if (stringmatchlen(pattern+1, patternLen-1,
26 string, stringLen, nocase))
27 return 1; /* match */
28 string++;
29 stringLen--;
30 }
31 return 0; /* no match */
32 break;
33 case '?':
34 if (stringLen == 0)
35 return 0; /* no match */
36 string++;
37 stringLen--;
38 break;
39 case '[':
40 {
41 int not, match;
42
43 pattern++;
44 patternLen--;
45 not = pattern[0] == '^';
46 if (not) {
47 pattern++;
48 patternLen--;
49 }
50 match = 0;
51 while(1) {
52 if (pattern[0] == '\\') {
53 pattern++;
54 patternLen--;
55 if (pattern[0] == string[0])
56 match = 1;
57 } else if (pattern[0] == ']') {
58 break;
59 } else if (patternLen == 0) {
60 pattern--;
61 patternLen++;
62 break;
63 } else if (pattern[1] == '-' && patternLen >= 3) {
64 int start = pattern[0];
65 int end = pattern[2];
66 int c = string[0];
67 if (start > end) {
68 int t = start;
69 start = end;
70 end = t;
71 }
72 if (nocase) {
73 start = tolower(start);
74 end = tolower(end);
75 c = tolower(c);
76 }
77 pattern += 2;
78 patternLen -= 2;
79 if (c >= start && c <= end)
80 match = 1;
81 } else {
82 if (!nocase) {
83 if (pattern[0] == string[0])
84 match = 1;
85 } else {
86 if (tolower((int)pattern[0]) == tolower((int)string[0]))
87 match = 1;
88 }
89 }
90 pattern++;
91 patternLen--;
92 }
93 if (not)
94 match = !match;
95 if (!match)
96 return 0; /* no match */
97 string++;
98 stringLen--;
99 break;
100 }
101 case '\\':
102 if (patternLen >= 2) {
103 pattern++;
104 patternLen--;
105 }
106 /* fall through */
107 default:
108 if (!nocase) {
109 if (pattern[0] != string[0])
110 return 0; /* no match */
111 } else {
112 if (tolower((int)pattern[0]) != tolower((int)string[0]))
113 return 0; /* no match */
114 }
115 string++;
116 stringLen--;
117 break;
118 }
119 pattern++;
120 patternLen--;
121 if (stringLen == 0) {
122 while(*pattern == '*') {
123 pattern++;
124 patternLen--;
125 }
126 break;
127 }
128 }
129 if (patternLen == 0 && stringLen == 0)
130 return 1;
131 return 0;
132}
133
134int stringmatch(const char *pattern, const char *string, int nocase) {
135 return stringmatchlen(pattern,strlen(pattern),string,strlen(string),nocase);
136}
137
138/* Convert a string representing an amount of memory into the number of
139 * bytes, so for instance memtoll("1Gi") will return 1073741824 that is
140 * (1024*1024*1024).
141 *
142 * On parsing error, if *err is not NULL, it's set to 1, otherwise it's
143 * set to 0 */
144long long memtoll(const char *p, int *err) {
145 const char *u;
146 char buf[128];
147 long mul; /* unit multiplier */
148 long long val;
149 unsigned int digits;
150
151 if (err) *err = 0;
152 /* Search the first non digit character. */
153 u = p;
154 if (*u == '-') u++;
155 while(*u && isdigit(*u)) u++;
156 if (*u == '\0' || !strcasecmp(u,"b")) {
157 mul = 1;
158 } else if (!strcasecmp(u,"k")) {
159 mul = 1000;
160 } else if (!strcasecmp(u,"kb")) {
161 mul = 1024;
162 } else if (!strcasecmp(u,"m")) {
163 mul = 1000*1000;
164 } else if (!strcasecmp(u,"mb")) {
165 mul = 1024*1024;
166 } else if (!strcasecmp(u,"g")) {
167 mul = 1000L*1000*1000;
168 } else if (!strcasecmp(u,"gb")) {
169 mul = 1024L*1024*1024;
170 } else {
171 if (err) *err = 1;
172 mul = 1;
173 }
174 digits = u-p;
175 if (digits >= sizeof(buf)) {
176 if (err) *err = 1;
177 return LLONG_MAX;
178 }
179 memcpy(buf,p,digits);
180 buf[digits] = '\0';
181 val = strtoll(buf,NULL,10);
182 return val*mul;
183}
184
185/* Convert a long long into a string. Returns the number of
186 * characters needed to represent the number, that can be shorter if passed
187 * buffer length is not enough to store the whole number. */
188int ll2string(char *s, size_t len, long long value) {
189 char buf[32], *p;
190 unsigned long long v;
191 size_t l;
192
193 if (len == 0) return 0;
194 v = (value < 0) ? -value : value;
195 p = buf+31; /* point to the last character */
196 do {
197 *p-- = '0'+(v%10);
198 v /= 10;
199 } while(v);
200 if (value < 0) *p-- = '-';
201 p++;
202 l = 32-(p-buf);
203 if (l+1 > len) l = len-1; /* Make sure it fits, including the nul term */
204 memcpy(s,p,l);
205 s[l] = '\0';
206 return l;
207}
208
d4e07f17
PN
209/* Convert a string into a long long. Returns 1 if the string could be parsed
210 * into a (non-overflowing) long long, 0 otherwise. The value will be set to
211 * the parsed value when appropriate. */
212int string2ll(char *s, size_t slen, long long *value) {
213 char *p = s;
214 size_t plen = 0;
215 int negative = 0;
216 unsigned long long v;
217
218 if (plen == slen)
219 return 0;
220
5d081931
PN
221 /* Special case: first and only digit is 0. */
222 if (slen == 1 && p[0] == '0') {
223 if (value != NULL) *value = 0;
224 return 1;
225 }
226
d4e07f17
PN
227 if (p[0] == '-') {
228 negative = 1;
229 p++; plen++;
230
231 /* Abort on only a negative sign. */
232 if (plen == slen)
233 return 0;
234 }
235
5cbe90db 236 /* First digit should be 1-9, otherwise the string should just be 0. */
d4e07f17
PN
237 if (p[0] >= '1' && p[0] <= '9') {
238 v = p[0]-'0';
239 p++; plen++;
5cbe90db 240 } else if (p[0] == '0' && slen == 1) {
241 *value = 0;
242 return 1;
d4e07f17
PN
243 } else {
244 return 0;
245 }
246
247 while (plen < slen && p[0] >= '0' && p[0] <= '9') {
248 if (v > (ULLONG_MAX / 10)) /* Overflow. */
249 return 0;
250 v *= 10;
251
252 if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */
253 return 0;
254 v += p[0]-'0';
255
256 p++; plen++;
257 }
258
259 /* Return if not all bytes were used. */
260 if (plen < slen)
261 return 0;
262
263 if (negative) {
5d081931 264 if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */
d4e07f17
PN
265 return 0;
266 if (value != NULL) *value = -v;
267 } else {
268 if (v > LLONG_MAX) /* Overflow. */
269 return 0;
270 if (value != NULL) *value = v;
271 }
272 return 1;
273}
274
5d081931
PN
275/* Convert a string into a long. Returns 1 if the string could be parsed into a
276 * (non-overflowing) long, 0 otherwise. The value will be set to the parsed
277 * value when appropriate. */
278int string2l(char *s, size_t slen, long *lval) {
279 long long llval;
280
281 if (!string2ll(s,slen,&llval))
282 return 0;
283
284 if (llval < LONG_MIN || llval > LONG_MAX)
285 return 0;
286
287 *lval = (long)llval;
288 return 1;
289}
290
672b0a1b
PN
291/* Convert a double to a string representation. Returns the number of bytes
292 * required. The representation should always be parsable by stdtod(3). */
293int d2string(char *buf, size_t len, double value) {
294 if (isnan(value)) {
295 len = snprintf(buf,len,"nan");
296 } else if (isinf(value)) {
297 if (value < 0)
298 len = snprintf(buf,len,"-inf");
299 else
300 len = snprintf(buf,len,"inf");
301 } else if (value == 0) {
302 /* See: http://en.wikipedia.org/wiki/Signed_zero, "Comparisons". */
303 if (1.0/value < 0)
304 len = snprintf(buf,len,"-0");
305 else
306 len = snprintf(buf,len,"0");
307 } else {
308#if (DBL_MANT_DIG >= 52) && (LLONG_MAX == 0x7fffffffffffffffLL)
309 /* Check if the float is in a safe range to be casted into a
310 * long long. We are assuming that long long is 64 bit here.
311 * Also we are assuming that there are no implementations around where
312 * double has precision < 52 bit.
313 *
314 * Under this assumptions we test if a double is inside an interval
315 * where casting to long long is safe. Then using two castings we
316 * make sure the decimal part is zero. If all this is true we use
317 * integer printing function that is much faster. */
318 double min = -4503599627370495; /* (2^52)-1 */
319 double max = 4503599627370496; /* -(2^52) */
320 if (val > min && val < max && value == ((double)((long long)value)))
321 len = ll2string(buf,len,(long long)value);
322 else
323#endif
324 len = snprintf(buf,len,"%.17g",value);
325 }
326
327 return len;
328}
329
5d081931
PN
330#ifdef UTIL_TEST_MAIN
331#include <assert.h>
332
333void test_string2ll(void) {
334 char buf[32];
335 long long v;
336
337 /* May not start with +. */
338 strcpy(buf,"+1");
339 assert(string2ll(buf,strlen(buf),&v) == 0);
340
3edbcab9
PN
341 /* Leading space. */
342 strcpy(buf," 1");
343 assert(string2ll(buf,strlen(buf),&v) == 0);
344
345 /* Trailing space. */
346 strcpy(buf,"1 ");
347 assert(string2ll(buf,strlen(buf),&v) == 0);
348
5d081931
PN
349 /* May not start with 0. */
350 strcpy(buf,"01");
351 assert(string2ll(buf,strlen(buf),&v) == 0);
352
353 strcpy(buf,"-1");
354 assert(string2ll(buf,strlen(buf),&v) == 1);
355 assert(v == -1);
356
357 strcpy(buf,"0");
358 assert(string2ll(buf,strlen(buf),&v) == 1);
359 assert(v == 0);
360
361 strcpy(buf,"1");
362 assert(string2ll(buf,strlen(buf),&v) == 1);
363 assert(v == 1);
364
365 strcpy(buf,"99");
366 assert(string2ll(buf,strlen(buf),&v) == 1);
367 assert(v == 99);
368
369 strcpy(buf,"-99");
370 assert(string2ll(buf,strlen(buf),&v) == 1);
371 assert(v == -99);
372
373 strcpy(buf,"-9223372036854775808");
374 assert(string2ll(buf,strlen(buf),&v) == 1);
375 assert(v == LLONG_MIN);
376
377 strcpy(buf,"-9223372036854775809"); /* overflow */
378 assert(string2ll(buf,strlen(buf),&v) == 0);
379
380 strcpy(buf,"9223372036854775807");
381 assert(string2ll(buf,strlen(buf),&v) == 1);
382 assert(v == LLONG_MAX);
383
384 strcpy(buf,"9223372036854775808"); /* overflow */
385 assert(string2ll(buf,strlen(buf),&v) == 0);
ec7e1389 386}
387
5d081931
PN
388void test_string2l(void) {
389 char buf[32];
390 long v;
391
392 /* May not start with +. */
393 strcpy(buf,"+1");
394 assert(string2l(buf,strlen(buf),&v) == 0);
395
396 /* May not start with 0. */
397 strcpy(buf,"01");
398 assert(string2l(buf,strlen(buf),&v) == 0);
399
400 strcpy(buf,"-1");
401 assert(string2l(buf,strlen(buf),&v) == 1);
402 assert(v == -1);
403
404 strcpy(buf,"0");
405 assert(string2l(buf,strlen(buf),&v) == 1);
406 assert(v == 0);
407
408 strcpy(buf,"1");
409 assert(string2l(buf,strlen(buf),&v) == 1);
410 assert(v == 1);
411
412 strcpy(buf,"99");
413 assert(string2l(buf,strlen(buf),&v) == 1);
414 assert(v == 99);
ec7e1389 415
5d081931
PN
416 strcpy(buf,"-99");
417 assert(string2l(buf,strlen(buf),&v) == 1);
418 assert(v == -99);
419
420#if LONG_MAX != LLONG_MAX
421 strcpy(buf,"-2147483648");
422 assert(string2l(buf,strlen(buf),&v) == 1);
423 assert(v == LONG_MIN);
424
425 strcpy(buf,"-2147483649"); /* overflow */
426 assert(string2l(buf,strlen(buf),&v) == 0);
427
428 strcpy(buf,"2147483647");
429 assert(string2l(buf,strlen(buf),&v) == 1);
430 assert(v == LONG_MAX);
431
432 strcpy(buf,"2147483648"); /* overflow */
433 assert(string2l(buf,strlen(buf),&v) == 0);
434#endif
e2641e09 435}
ec7e1389 436
5d081931
PN
437int main(int argc, char **argv) {
438 test_string2ll();
439 test_string2l();
440 return 0;
ec7e1389 441}
5d081931 442#endif