LCOV - code coverage report
Current view: directory - redis/src - util.c (source / functions) Found Hit Coverage
Test: redis.info Lines: 210 99 47.1 %
Date: 2012-04-04 Functions: 8 7 87.5 %
Colors: not hit hit

       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                 : #include <unistd.h>
       9                 : #include <sys/time.h>
      10                 : 
      11                 : #include "util.h"
      12                 : 
      13                 : /* Glob-style pattern matching. */
      14              21 : int stringmatchlen(const char *pattern, int patternLen,
      15                 :         const char *string, int stringLen, int nocase)
      16                 : {
      17              83 :     while(patternLen) {
      18              62 :         switch(pattern[0]) {
      19                 :         case '*':
      20               9 :             while (pattern[1] == '*') {
      21               0 :                 pattern++;
      22               0 :                 patternLen--;
      23                 :             }
      24               9 :             if (patternLen == 1)
      25               9 :                 return 1; /* match */
      26               0 :             while(stringLen) {
      27               0 :                 if (stringmatchlen(pattern+1, patternLen-1,
      28                 :                             string, stringLen, nocase))
      29               0 :                     return 1; /* match */
      30               0 :                 string++;
      31               0 :                 stringLen--;
      32                 :             }
      33               0 :             return 0; /* no match */
      34                 :             break;
      35                 :         case '?':
      36               0 :             if (stringLen == 0)
      37               0 :                 return 0; /* no match */
      38               0 :             string++;
      39               0 :             stringLen--;
      40               0 :             break;
      41                 :         case '[':
      42                 :         {
      43                 :             int not, match;
      44                 : 
      45               0 :             pattern++;
      46               0 :             patternLen--;
      47               0 :             not = pattern[0] == '^';
      48               0 :             if (not) {
      49               0 :                 pattern++;
      50               0 :                 patternLen--;
      51                 :             }
      52               0 :             match = 0;
      53                 :             while(1) {
      54               0 :                 if (pattern[0] == '\\') {
      55               0 :                     pattern++;
      56               0 :                     patternLen--;
      57               0 :                     if (pattern[0] == string[0])
      58               0 :                         match = 1;
      59               0 :                 } else if (pattern[0] == ']') {
      60                 :                     break;
      61               0 :                 } else if (patternLen == 0) {
      62               0 :                     pattern--;
      63               0 :                     patternLen++;
      64               0 :                     break;
      65               0 :                 } else if (pattern[1] == '-' && patternLen >= 3) {
      66               0 :                     int start = pattern[0];
      67               0 :                     int end = pattern[2];
      68               0 :                     int c = string[0];
      69               0 :                     if (start > end) {
      70               0 :                         int t = start;
      71               0 :                         start = end;
      72               0 :                         end = t;
      73                 :                     }
      74               0 :                     if (nocase) {
      75               0 :                         start = tolower(start);
      76               0 :                         end = tolower(end);
      77               0 :                         c = tolower(c);
      78                 :                     }
      79               0 :                     pattern += 2;
      80               0 :                     patternLen -= 2;
      81               0 :                     if (c >= start && c <= end)
      82               0 :                         match = 1;
      83                 :                 } else {
      84               0 :                     if (!nocase) {
      85               0 :                         if (pattern[0] == string[0])
      86               0 :                             match = 1;
      87                 :                     } else {
      88               0 :                         if (tolower((int)pattern[0]) == tolower((int)string[0]))
      89               0 :                             match = 1;
      90                 :                     }
      91                 :                 }
      92               0 :                 pattern++;
      93               0 :                 patternLen--;
      94               0 :             }
      95               0 :             if (not)
      96               0 :                 match = !match;
      97               0 :             if (!match)
      98               0 :                 return 0; /* no match */
      99               0 :             string++;
     100               0 :             stringLen--;
     101               0 :             break;
     102                 :         }
     103                 :         case '\\':
     104               0 :             if (patternLen >= 2) {
     105               0 :                 pattern++;
     106               0 :                 patternLen--;
     107                 :             }
     108                 :             /* fall through */
     109                 :         default:
     110              53 :             if (!nocase) {
     111              53 :                 if (pattern[0] != string[0])
     112              12 :                     return 0; /* no match */
     113                 :             } else {
     114               0 :                 if (tolower((int)pattern[0]) != tolower((int)string[0]))
     115               0 :                     return 0; /* no match */
     116                 :             }
     117              41 :             string++;
     118              41 :             stringLen--;
     119                 :             break;
     120                 :         }
     121              41 :         pattern++;
     122              41 :         patternLen--;
     123              41 :         if (stringLen == 0) {
     124               0 :             while(*pattern == '*') {
     125               0 :                 pattern++;
     126               0 :                 patternLen--;
     127                 :             }
     128                 :             break;
     129                 :         }
     130                 :     }
     131               0 :     if (patternLen == 0 && stringLen == 0)
     132               0 :         return 1;
     133               0 :     return 0;
     134                 : }
     135                 : 
     136               0 : int stringmatch(const char *pattern, const char *string, int nocase) {
     137               0 :     return stringmatchlen(pattern,strlen(pattern),string,strlen(string),nocase);
     138                 : }
     139                 : 
     140                 : /* Convert a string representing an amount of memory into the number of
     141                 :  * bytes, so for instance memtoll("1Gi") will return 1073741824 that is
     142                 :  * (1024*1024*1024).
     143                 :  *
     144                 :  * On parsing error, if *err is not NULL, it's set to 1, otherwise it's
     145                 :  * set to 0 */
     146             265 : long long memtoll(const char *p, int *err) {
     147                 :     const char *u;
     148                 :     char buf[128];
     149                 :     long mul; /* unit multiplier */
     150                 :     long long val;
     151                 :     unsigned int digits;
     152                 : 
     153             265 :     if (err) *err = 0;
     154                 :     /* Search the first non digit character. */
     155             265 :     u = p;
     156             265 :     if (*u == '-') u++;
     157             688 :     while(*u && isdigit(*u)) u++;
     158             530 :     if (*u == '\0' || !strcasecmp(u,"b")) {
     159             265 :         mul = 1;
     160               0 :     } else if (!strcasecmp(u,"k")) {
     161               0 :         mul = 1000;
     162               0 :     } else if (!strcasecmp(u,"kb")) {
     163               0 :         mul = 1024;
     164               0 :     } else if (!strcasecmp(u,"m")) {
     165               0 :         mul = 1000*1000;
     166               0 :     } else if (!strcasecmp(u,"mb")) {
     167               0 :         mul = 1024*1024;
     168               0 :     } else if (!strcasecmp(u,"g")) {
     169               0 :         mul = 1000L*1000*1000;
     170               0 :     } else if (!strcasecmp(u,"gb")) {
     171               0 :         mul = 1024L*1024*1024;
     172                 :     } else {
     173               0 :         if (err) *err = 1;
     174               0 :         mul = 1;
     175                 :     }
     176             265 :     digits = u-p;
     177             265 :     if (digits >= sizeof(buf)) {
     178               0 :         if (err) *err = 1;
     179               0 :         return LLONG_MAX;
     180                 :     }
     181             265 :     memcpy(buf,p,digits);
     182             265 :     buf[digits] = '\0';
     183             265 :     val = strtoll(buf,NULL,10);
     184             265 :     return val*mul;
     185                 : }
     186                 : 
     187                 : /* Convert a long long into a string. Returns the number of
     188                 :  * characters needed to represent the number, that can be shorter if passed
     189                 :  * buffer length is not enough to store the whole number. */
     190          956054 : int ll2string(char *s, size_t len, long long value) {
     191                 :     char buf[32], *p;
     192                 :     unsigned long long v;
     193                 :     size_t l;
     194                 : 
     195          956054 :     if (len == 0) return 0;
     196          956054 :     v = (value < 0) ? -value : value;
     197          956054 :     p = buf+31; /* point to the last character */
     198                 :     do {
     199         5566455 :         *p-- = '0'+(v%10);
     200         5566455 :         v /= 10;
     201         5566455 :     } while(v);
     202          956054 :     if (value < 0) *p-- = '-';
     203          956054 :     p++;
     204          956054 :     l = 32-(p-buf);
     205          956054 :     if (l+1 > len) l = len-1; /* Make sure it fits, including the nul term */
     206                 :     memcpy(s,p,l);
     207          956054 :     s[l] = '\0';
     208          956054 :     return l;
     209                 : }
     210                 : 
     211                 : /* Convert a string into a long long. Returns 1 if the string could be parsed
     212                 :  * into a (non-overflowing) long long, 0 otherwise. The value will be set to
     213                 :  * the parsed value when appropriate. */
     214        10149190 : int string2ll(const char *s, size_t slen, long long *value) {
     215        10149190 :     const char *p = s;
     216        10149190 :     size_t plen = 0;
     217        10149190 :     int negative = 0;
     218                 :     unsigned long long v;
     219                 : 
     220        10149190 :     if (plen == slen)
     221             699 :         return 0;
     222                 : 
     223                 :     /* Special case: first and only digit is 0. */
     224        10148491 :     if (slen == 1 && p[0] == '0') {
     225            3781 :         if (value != NULL) *value = 0;
     226            3781 :         return 1;
     227                 :     }
     228                 : 
     229        10144710 :     if (p[0] == '-') {
     230            3594 :         negative = 1;
     231            3594 :         p++; plen++;
     232                 : 
     233                 :         /* Abort on only a negative sign. */
     234            3594 :         if (plen == slen)
     235               2 :             return 0;
     236                 :     }
     237                 : 
     238                 :     /* First digit should be 1-9, otherwise the string should just be 0. */
     239        10144708 :     if (p[0] >= '1' && p[0] <= '9') {
     240         8215826 :         v = p[0]-'0';
     241         8215826 :         p++; plen++;
     242         1928882 :     } else if (p[0] == '0' && slen == 1) {
     243               0 :         *value = 0;
     244               0 :         return 1;
     245                 :     } else {
     246         1928882 :         return 0;
     247                 :     }
     248                 : 
     249        23824252 :     while (plen < slen && p[0] >= '0' && p[0] <= '9') {
     250         7402618 :         if (v > (ULLONG_MAX / 10)) /* Overflow. */
     251           10018 :             return 0;
     252         7392600 :         v *= 10;
     253                 : 
     254         7392600 :         if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */
     255               0 :             return 0;
     256         7392600 :         v += p[0]-'0';
     257                 : 
     258         7392600 :         p++; plen++;
     259                 :     }
     260                 : 
     261                 :     /* Return if not all bytes were used. */
     262         8205808 :     if (plen < slen)
     263            4156 :         return 0;
     264                 : 
     265         8201652 :     if (negative) {
     266            2169 :         if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */
     267               0 :             return 0;
     268            2169 :         if (value != NULL) *value = -v;
     269                 :     } else {
     270         8199483 :         if (v > LLONG_MAX) /* Overflow. */
     271              27 :             return 0;
     272         8199456 :         if (value != NULL) *value = v;
     273                 :     }
     274         8201625 :     return 1;
     275                 : }
     276                 : 
     277                 : /* Convert a string into a long. Returns 1 if the string could be parsed into a
     278                 :  * (non-overflowing) long, 0 otherwise. The value will be set to the parsed
     279                 :  * value when appropriate. */
     280         2067775 : int string2l(const char *s, size_t slen, long *lval) {
     281                 :     long long llval;
     282                 : 
     283         2067775 :     if (!string2ll(s,slen,&llval))
     284         1857780 :         return 0;
     285                 : 
     286                 :     if (llval < LONG_MIN || llval > LONG_MAX)
     287                 :         return 0;
     288                 : 
     289          209995 :     *lval = (long)llval;
     290          209995 :     return 1;
     291                 : }
     292                 : 
     293                 : /* Convert a double to a string representation. Returns the number of bytes
     294                 :  * required. The representation should always be parsable by stdtod(3). */
     295           20169 : int d2string(char *buf, size_t len, double value) {
     296           20169 :     if (isnan(value)) {
     297               0 :         len = snprintf(buf,len,"nan");
     298           20169 :     } else if (isinf(value)) {
     299            2863 :         if (value < 0)
     300            2716 :             len = snprintf(buf,len,"-inf");
     301                 :         else
     302            3010 :             len = snprintf(buf,len,"inf");
     303           17306 :     } else if (value == 0) {
     304                 :         /* See: http://en.wikipedia.org/wiki/Signed_zero, "Comparisons". */
     305              15 :         if (1.0/value < 0)
     306               0 :             len = snprintf(buf,len,"-0");
     307                 :         else
     308              30 :             len = snprintf(buf,len,"0");
     309                 :     } else {
     310                 : #if (DBL_MANT_DIG >= 52) && (LLONG_MAX == 0x7fffffffffffffffLL)
     311                 :         /* Check if the float is in a safe range to be casted into a
     312                 :          * long long. We are assuming that long long is 64 bit here.
     313                 :          * Also we are assuming that there are no implementations around where
     314                 :          * double has precision < 52 bit.
     315                 :          *
     316                 :          * Under this assumptions we test if a double is inside an interval
     317                 :          * where casting to long long is safe. Then using two castings we
     318                 :          * make sure the decimal part is zero. If all this is true we use
     319                 :          * integer printing function that is much faster. */
     320                 :         double min = -4503599627370495; /* (2^52)-1 */
     321                 :         double max = 4503599627370496; /* -(2^52) */
     322                 :         if (val > min && val < max && value == ((double)((long long)value)))
     323                 :             len = ll2string(buf,len,(long long)value);
     324                 :         else
     325                 : #endif
     326           34582 :             len = snprintf(buf,len,"%.17g",value);
     327                 :     }
     328                 : 
     329           20169 :     return len;
     330                 : }
     331                 : 
     332                 : /* Generate the Redis "Run ID", a SHA1-sized random number that identifies a
     333                 :  * given execution of Redis, so that if you are talking with an instance
     334                 :  * having run_id == A, and you reconnect and it has run_id == B, you can be
     335                 :  * sure that it is either a different instance or it was restarted. */
     336              53 : void getRandomHexChars(char *p, unsigned int len) {
     337              53 :     FILE *fp = fopen("/dev/urandom","r");
     338              53 :     char *charset = "0123456789abcdef";
     339                 :     unsigned int j;
     340                 : 
     341             106 :     if (fp == NULL || fread(p,len,1,fp) == 0) {
     342                 :         /* If we can't read from /dev/urandom, do some reasonable effort
     343                 :          * in order to create some entropy, since this function is used to
     344                 :          * generate run_id and cluster instance IDs */
     345               0 :         char *x = p;
     346               0 :         unsigned int l = len;
     347                 :         struct timeval tv;
     348               0 :         pid_t pid = getpid();
     349                 : 
     350                 :         /* Use time and PID to fill the initial array. */
     351               0 :         gettimeofday(&tv,NULL);
     352               0 :         if (l >= sizeof(tv.tv_usec)) {
     353                 :             memcpy(x,&tv.tv_usec,sizeof(tv.tv_usec));
     354               0 :             l -= sizeof(tv.tv_usec);
     355               0 :             x += sizeof(tv.tv_usec);
     356                 :         }
     357               0 :         if (l >= sizeof(tv.tv_sec)) {
     358                 :             memcpy(x,&tv.tv_sec,sizeof(tv.tv_sec));
     359               0 :             l -= sizeof(tv.tv_sec);
     360               0 :             x += sizeof(tv.tv_sec);
     361                 :         }
     362               0 :         if (l >= sizeof(pid)) {
     363                 :             memcpy(x,&pid,sizeof(pid));
     364               0 :             l -= sizeof(pid);
     365               0 :             x += sizeof(pid);
     366                 :         }
     367                 :         /* Finally xor it with rand() output, that was already seeded with
     368                 :          * time() at startup. */
     369               0 :         for (j = 0; j < len; j++)
     370               0 :             p[j] ^= rand();
     371                 :     }
     372                 :     /* Turn it into hex digits taking just 4 bits out of 8 for every byte. */
     373            2173 :     for (j = 0; j < len; j++)
     374            2120 :         p[j] = charset[p[j] & 0x0F];
     375              53 :     fclose(fp);
     376              53 : }
     377                 : 
     378                 : #ifdef UTIL_TEST_MAIN
     379                 : #include <assert.h>
     380                 : 
     381                 : void test_string2ll(void) {
     382                 :     char buf[32];
     383                 :     long long v;
     384                 : 
     385                 :     /* May not start with +. */
     386                 :     strcpy(buf,"+1");
     387                 :     assert(string2ll(buf,strlen(buf),&v) == 0);
     388                 : 
     389                 :     /* Leading space. */
     390                 :     strcpy(buf," 1");
     391                 :     assert(string2ll(buf,strlen(buf),&v) == 0);
     392                 : 
     393                 :     /* Trailing space. */
     394                 :     strcpy(buf,"1 ");
     395                 :     assert(string2ll(buf,strlen(buf),&v) == 0);
     396                 : 
     397                 :     /* May not start with 0. */
     398                 :     strcpy(buf,"01");
     399                 :     assert(string2ll(buf,strlen(buf),&v) == 0);
     400                 : 
     401                 :     strcpy(buf,"-1");
     402                 :     assert(string2ll(buf,strlen(buf),&v) == 1);
     403                 :     assert(v == -1);
     404                 : 
     405                 :     strcpy(buf,"0");
     406                 :     assert(string2ll(buf,strlen(buf),&v) == 1);
     407                 :     assert(v == 0);
     408                 : 
     409                 :     strcpy(buf,"1");
     410                 :     assert(string2ll(buf,strlen(buf),&v) == 1);
     411                 :     assert(v == 1);
     412                 : 
     413                 :     strcpy(buf,"99");
     414                 :     assert(string2ll(buf,strlen(buf),&v) == 1);
     415                 :     assert(v == 99);
     416                 : 
     417                 :     strcpy(buf,"-99");
     418                 :     assert(string2ll(buf,strlen(buf),&v) == 1);
     419                 :     assert(v == -99);
     420                 : 
     421                 :     strcpy(buf,"-9223372036854775808");
     422                 :     assert(string2ll(buf,strlen(buf),&v) == 1);
     423                 :     assert(v == LLONG_MIN);
     424                 : 
     425                 :     strcpy(buf,"-9223372036854775809"); /* overflow */
     426                 :     assert(string2ll(buf,strlen(buf),&v) == 0);
     427                 : 
     428                 :     strcpy(buf,"9223372036854775807");
     429                 :     assert(string2ll(buf,strlen(buf),&v) == 1);
     430                 :     assert(v == LLONG_MAX);
     431                 : 
     432                 :     strcpy(buf,"9223372036854775808"); /* overflow */
     433                 :     assert(string2ll(buf,strlen(buf),&v) == 0);
     434                 : }
     435                 : 
     436                 : void test_string2l(void) {
     437                 :     char buf[32];
     438                 :     long v;
     439                 : 
     440                 :     /* May not start with +. */
     441                 :     strcpy(buf,"+1");
     442                 :     assert(string2l(buf,strlen(buf),&v) == 0);
     443                 : 
     444                 :     /* May not start with 0. */
     445                 :     strcpy(buf,"01");
     446                 :     assert(string2l(buf,strlen(buf),&v) == 0);
     447                 : 
     448                 :     strcpy(buf,"-1");
     449                 :     assert(string2l(buf,strlen(buf),&v) == 1);
     450                 :     assert(v == -1);
     451                 : 
     452                 :     strcpy(buf,"0");
     453                 :     assert(string2l(buf,strlen(buf),&v) == 1);
     454                 :     assert(v == 0);
     455                 : 
     456                 :     strcpy(buf,"1");
     457                 :     assert(string2l(buf,strlen(buf),&v) == 1);
     458                 :     assert(v == 1);
     459                 : 
     460                 :     strcpy(buf,"99");
     461                 :     assert(string2l(buf,strlen(buf),&v) == 1);
     462                 :     assert(v == 99);
     463                 : 
     464                 :     strcpy(buf,"-99");
     465                 :     assert(string2l(buf,strlen(buf),&v) == 1);
     466                 :     assert(v == -99);
     467                 : 
     468                 : #if LONG_MAX != LLONG_MAX
     469                 :     strcpy(buf,"-2147483648");
     470                 :     assert(string2l(buf,strlen(buf),&v) == 1);
     471                 :     assert(v == LONG_MIN);
     472                 : 
     473                 :     strcpy(buf,"-2147483649"); /* overflow */
     474                 :     assert(string2l(buf,strlen(buf),&v) == 0);
     475                 : 
     476                 :     strcpy(buf,"2147483647");
     477                 :     assert(string2l(buf,strlen(buf),&v) == 1);
     478                 :     assert(v == LONG_MAX);
     479                 : 
     480                 :     strcpy(buf,"2147483648"); /* overflow */
     481                 :     assert(string2l(buf,strlen(buf),&v) == 0);
     482                 : #endif
     483                 : }
     484                 : 
     485                 : int main(int argc, char **argv) {
     486                 :     test_string2ll();
     487                 :     test_string2l();
     488                 :     return 0;
     489                 : }
     490                 : #endif

Generated by: LCOV version 1.7