xref: /redis-3.2.3/src/util.c (revision 80586cb8)
1 #include "fmacros.h"
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <ctype.h>
6 #include <limits.h>
7 #include <math.h>
8 
9 #include "util.h"
10 
11 /* Glob-style pattern matching. */
12 int 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 
134 int 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 */
144 long 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. */
188 int 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 
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. */
212 int string2ll(const char *s, size_t slen, long long *value) {
213     const 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 
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 
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 
236     /* First digit should be 1-9, otherwise the string should just be 0. */
237     if (p[0] >= '1' && p[0] <= '9') {
238         v = p[0]-'0';
239         p++; plen++;
240     } else if (p[0] == '0' && slen == 1) {
241         *value = 0;
242         return 1;
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) {
264         if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */
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 
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. */
278 int string2l(const 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 
291 /* Convert a double to a string representation. Returns the number of bytes
292  * required. The representation should always be parsable by stdtod(3). */
293 int 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 
330 #ifdef UTIL_TEST_MAIN
331 #include <assert.h>
332 
333 void 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 
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 
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);
386 }
387 
388 void 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);
415 
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
435 }
436 
437 int main(int argc, char **argv) {
438     test_string2ll();
439     test_string2l();
440     return 0;
441 }
442 #endif
443