Redis-util 转换函数

来源:互联网 发布:大司马淘宝 编辑:程序博客网 时间:2024/06/16 04:46
#include "fmacros.h"#include <stdlib.h>#include <stdio.h>#include <string.h>#include <ctype.h>#include <limits.h>#include <math.h>#include <unistd.h>#include <sys/time.h>#include <float.h>#include "util.h"----------/* Glob-style pattern matching. */int stringmatchlen(const char *pattern, int patternLen,        const char *string, int stringLen, int nocase){    while(patternLen) {        switch(pattern[0]) {        case '*':            while (pattern[1] == '*') {                pattern++;                patternLen--;            }            if (patternLen == 1)                return 1; /* match */            while(stringLen) {                if (stringmatchlen(pattern+1, patternLen-1,                            string, stringLen, nocase))                    return 1; /* match */                string++;                stringLen--;            }            return 0; /* no match */            break;        case '?':            if (stringLen == 0)                return 0; /* no match */            string++;            stringLen--;            break;        case '[':        {            int not, match;            pattern++;            patternLen--;            not = pattern[0] == '^';            if (not) {                pattern++;                patternLen--;            }            match = 0;            while(1) {                if (pattern[0] == '\\') {                    pattern++;                    patternLen--;                    if (pattern[0] == string[0])                        match = 1;                } else if (pattern[0] == ']') {                    break;                } else if (patternLen == 0) {                    pattern--;                    patternLen++;                    break;                } else if (pattern[1] == '-' && patternLen >= 3) {                    int start = pattern[0];                    int end = pattern[2];                    int c = string[0];                    if (start > end) {                        int t = start;                        start = end;                        end = t;                    }                    if (nocase) {                        start = tolower(start);                        end = tolower(end);                        c = tolower(c);                    }                    pattern += 2;                    patternLen -= 2;                    if (c >= start && c <= end)                        match = 1;                } else {                    if (!nocase) {                        if (pattern[0] == string[0])                            match = 1;                    } else {                        if (tolower((int)pattern[0]) == tolower((int)string[0]))                            match = 1;                    }                }                pattern++;                patternLen--;            }            if (not)                match = !match;            if (!match)                return 0; /* no match */            string++;            stringLen--;            break;        }        case '\\':            if (patternLen >= 2) {                pattern++;                patternLen--;            }            /* fall through */        default:            if (!nocase) {                if (pattern[0] != string[0])                    return 0; /* no match */            } else {                if (tolower((int)pattern[0]) != tolower((int)string[0]))                    return 0; /* no match */            }            string++;            stringLen--;            break;        }        pattern++;        patternLen--;        if (stringLen == 0) {            while(*pattern == '*') {                pattern++;                patternLen--;            }            break;        }    }    if (patternLen == 0 && stringLen == 0)        return 1;    return 0;}int stringmatch(const char *pattern, const char *string, int nocase) {    return stringmatchlen(pattern,strlen(pattern),string,strlen(string),nocase);}/* Convert a string representing an amount of memory into the number of * bytes, so for instance memtoll("1Gi") will return 1073741824 that is * (1024*1024*1024). * * On parsing error, if *err is not NULL, it's set to 1, otherwise it's * set to 0 */long long memtoll(const char *p, int *err) {    const char *u;    char buf[128];    long mul; /* unit multiplier */    long long val;    unsigned int digits;    if (err) *err = 0;    /* Search the first non digit character. */    u = p;    if (*u == '-') u++;    while(*u && isdigit(*u)) u++;    if (*u == '\0' || !strcasecmp(u,"b")) {        mul = 1;    } else if (!strcasecmp(u,"k")) {        mul = 1000;    } else if (!strcasecmp(u,"kb")) {        mul = 1024;    } else if (!strcasecmp(u,"m")) {        mul = 1000*1000;    } else if (!strcasecmp(u,"mb")) {        mul = 1024*1024;    } else if (!strcasecmp(u,"g")) {        mul = 1000L*1000*1000;    } else if (!strcasecmp(u,"gb")) {        mul = 1024L*1024*1024;    } else {        if (err) *err = 1;        mul = 1;    }    digits = u-p;    if (digits >= sizeof(buf)) {        if (err) *err = 1;        return LLONG_MAX;    }    memcpy(buf,p,digits);    buf[digits] = '\0';    val = strtoll(buf,NULL,10);    return val*mul;}/* Convert a long long into a string. Returns the number of * characters needed to represent the number, that can be shorter if passed * buffer length is not enough to store the whole number. */int ll2string(char *s, size_t len, long long value) {    char buf[32], *p;    unsigned long long v;    size_t l;    if (len == 0) return 0;    v = (value < 0) ? -value : value;    p = buf+31; /* point to the last character */    do {        *p-- = '0'+(v%10);        v /= 10;    } while(v);    if (value < 0) *p-- = '-';    p++;    l = 32-(p-buf);    if (l+1 > len) l = len-1; /* Make sure it fits, including the nul term */    memcpy(s,p,l);    s[l] = '\0';    return l;}/* Convert a string into a long long. Returns 1 if the string could be parsed * into a (non-overflowing) long long, 0 otherwise. The value will be set to * the parsed value when appropriate. */int string2ll(const char *s, size_t slen, long long *value) {    const char *p = s;    size_t plen = 0;    int negative = 0;    unsigned long long v;    if (plen == slen)        return 0;    /* Special case: first and only digit is 0. */    if (slen == 1 && p[0] == '0') {        if (value != NULL) *value = 0;        return 1;    }    if (p[0] == '-') {        negative = 1;        p++; plen++;        /* Abort on only a negative sign. */        if (plen == slen)            return 0;    }    /* First digit should be 1-9, otherwise the string should just be 0. */    if (p[0] >= '1' && p[0] <= '9') {        v = p[0]-'0';        p++; plen++;    } else if (p[0] == '0' && slen == 1) {        *value = 0;        return 1;    } else {        return 0;    }    while (plen < slen && p[0] >= '0' && p[0] <= '9') {        if (v > (ULLONG_MAX / 10)) /* Overflow. */            return 0;        v *= 10;        if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */            return 0;        v += p[0]-'0';        p++; plen++;    }    /* Return if not all bytes were used. */    if (plen < slen)        return 0;    if (negative) {        if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */            return 0;        if (value != NULL) *value = -v;    } else {        if (v > LLONG_MAX) /* Overflow. */            return 0;        if (value != NULL) *value = v;    }    return 1;}/* Convert a string into a long. Returns 1 if the string could be parsed into a * (non-overflowing) long, 0 otherwise. The value will be set to the parsed * value when appropriate. */int string2l(const char *s, size_t slen, long *lval) {    long long llval;    if (!string2ll(s,slen,&llval))        return 0;    if (llval < LONG_MIN || llval > LONG_MAX)        return 0;    *lval = (long)llval;    return 1;}/* Convert a double to a string representation. Returns the number of bytes * required. The representation should always be parsable by stdtod(3). */int d2string(char *buf, size_t len, double value) {    if (isnan(value)) {        len = snprintf(buf,len,"nan");    } else if (isinf(value)) {        if (value < 0)            len = snprintf(buf,len,"-inf");        else            len = snprintf(buf,len,"inf");    } else if (value == 0) {        /* See: http://en.wikipedia.org/wiki/Signed_zero, "Comparisons". */        if (1.0/value < 0)            len = snprintf(buf,len,"-0");        else            len = snprintf(buf,len,"0");    } else {#if (DBL_MANT_DIG >= 52) && (LLONG_MAX == 0x7fffffffffffffffLL)        /* Check if the float is in a safe range to be casted into a         * long long. We are assuming that long long is 64 bit here.         * Also we are assuming that there are no implementations around where         * double has precision < 52 bit.         *         * Under this assumptions we test if a double is inside an interval         * where casting to long long is safe. Then using two castings we         * make sure the decimal part is zero. If all this is true we use         * integer printing function that is much faster. */        double min = -4503599627370495; /* (2^52)-1 */        double max = 4503599627370496; /* -(2^52) */        if (value > min && value < max && value == ((double)((long long)value)))            len = ll2string(buf,len,(long long)value);        else#endif            len = snprintf(buf,len,"%.17g",value);    }    return len;}/* Generate the Redis "Run ID", a SHA1-sized random number that identifies a * given execution of Redis, so that if you are talking with an instance * having run_id == A, and you reconnect and it has run_id == B, you can be * sure that it is either a different instance or it was restarted. */void getRandomHexChars(char *p, unsigned int len) {    FILE *fp = fopen("/dev/urandom","r");    char *charset = "0123456789abcdef";    unsigned int j;    if (fp == NULL || fread(p,len,1,fp) == 0) {        /* If we can't read from /dev/urandom, do some reasonable effort         * in order to create some entropy, since this function is used to         * generate run_id and cluster instance IDs */        char *x = p;        unsigned int l = len;        struct timeval tv;        pid_t pid = getpid();        /* Use time and PID to fill the initial array. */        gettimeofday(&tv,NULL);        if (l >= sizeof(tv.tv_usec)) {            memcpy(x,&tv.tv_usec,sizeof(tv.tv_usec));            l -= sizeof(tv.tv_usec);            x += sizeof(tv.tv_usec);        }        if (l >= sizeof(tv.tv_sec)) {            memcpy(x,&tv.tv_sec,sizeof(tv.tv_sec));            l -= sizeof(tv.tv_sec);            x += sizeof(tv.tv_sec);        }        if (l >= sizeof(pid)) {            memcpy(x,&pid,sizeof(pid));            l -= sizeof(pid);            x += sizeof(pid);        }        /* Finally xor it with rand() output, that was already seeded with         * time() at startup. */        for (j = 0; j < len; j++)            p[j] ^= rand();    }    /* Turn it into hex digits taking just 4 bits out of 8 for every byte. */    for (j = 0; j < len; j++)        p[j] = charset[p[j] & 0x0F];    if (fp) fclose(fp);}/* Given the filename, return the absolute path as an SDS string, or NULL * if it fails for some reason. Note that "filename" may be an absolute path * already, this will be detected and handled correctly. * * The function does not try to normalize everything, but only the obvious * case of one or more "../" appearning at the start of "filename" * relative path. */sds getAbsolutePath(char *filename) {    char cwd[1024];    sds abspath;    sds relpath = sdsnew(filename);    relpath = sdstrim(relpath," \r\n\t");    if (relpath[0] == '/') return relpath; /* Path is already absolute. */    /* If path is relative, join cwd and relative path. */    if (getcwd(cwd,sizeof(cwd)) == NULL) {        sdsfree(relpath);        return NULL;    }    abspath = sdsnew(cwd);    if (sdslen(abspath) && abspath[sdslen(abspath)-1] != '/')        abspath = sdscat(abspath,"/");    /* At this point we have the current path always ending with "/", and     * the trimmed relative path. Try to normalize the obvious case of     * trailing ../ elements at the start of the path.     *     * For every "../" we find in the filename, we remove it and also remove     * the last element of the cwd, unless the current cwd is "/". */    while (sdslen(relpath) >= 3 &&           relpath[0] == '.' && relpath[1] == '.' && relpath[2] == '/')    {        sdsrange(relpath,3,-1);        if (sdslen(abspath) > 1) {            char *p = abspath + sdslen(abspath)-2;            int trimlen = 1;            while(*p != '/') {                p--;                trimlen++;            }            sdsrange(abspath,0,-(trimlen+1));        }    }    /* Finally glue the two parts together. */    abspath = sdscatsds(abspath,relpath);    sdsfree(relpath);    return abspath;}/* Return true if the specified path is just a file basename without any * relative or absolute path. This function just checks that no / or \ * character exists inside the specified path, that's enough in the * environments where Redis runs. */int pathIsBaseName(char *path) {    return strchr(path,'/') == NULL && strchr(path,'\\') == NULL;}#ifdef UTIL_TEST_MAIN#include <assert.h>void test_string2ll(void) {    char buf[32];    long long v;    /* May not start with +. */    strcpy(buf,"+1");    assert(string2ll(buf,strlen(buf),&v) == 0);    /* Leading space. */    strcpy(buf," 1");    assert(string2ll(buf,strlen(buf),&v) == 0);    /* Trailing space. */    strcpy(buf,"1 ");    assert(string2ll(buf,strlen(buf),&v) == 0);    /* May not start with 0. */    strcpy(buf,"01");    assert(string2ll(buf,strlen(buf),&v) == 0);    strcpy(buf,"-1");    assert(string2ll(buf,strlen(buf),&v) == 1);    assert(v == -1);    strcpy(buf,"0");    assert(string2ll(buf,strlen(buf),&v) == 1);    assert(v == 0);    strcpy(buf,"1");    assert(string2ll(buf,strlen(buf),&v) == 1);    assert(v == 1);    strcpy(buf,"99");    assert(string2ll(buf,strlen(buf),&v) == 1);    assert(v == 99);    strcpy(buf,"-99");    assert(string2ll(buf,strlen(buf),&v) == 1);    assert(v == -99);    strcpy(buf,"-9223372036854775808");    assert(string2ll(buf,strlen(buf),&v) == 1);    assert(v == LLONG_MIN);    strcpy(buf,"-9223372036854775809"); /* overflow */    assert(string2ll(buf,strlen(buf),&v) == 0);    strcpy(buf,"9223372036854775807");    assert(string2ll(buf,strlen(buf),&v) == 1);    assert(v == LLONG_MAX);    strcpy(buf,"9223372036854775808"); /* overflow */    assert(string2ll(buf,strlen(buf),&v) == 0);}void test_string2l(void) {    char buf[32];    long v;    /* May not start with +. */    strcpy(buf,"+1");    assert(string2l(buf,strlen(buf),&v) == 0);    /* May not start with 0. */    strcpy(buf,"01");    assert(string2l(buf,strlen(buf),&v) == 0);    strcpy(buf,"-1");    assert(string2l(buf,strlen(buf),&v) == 1);    assert(v == -1);    strcpy(buf,"0");    assert(string2l(buf,strlen(buf),&v) == 1);    assert(v == 0);    strcpy(buf,"1");    assert(string2l(buf,strlen(buf),&v) == 1);    assert(v == 1);    strcpy(buf,"99");    assert(string2l(buf,strlen(buf),&v) == 1);    assert(v == 99);    strcpy(buf,"-99");    assert(string2l(buf,strlen(buf),&v) == 1);    assert(v == -99);#if LONG_MAX != LLONG_MAX    strcpy(buf,"-2147483648");    assert(string2l(buf,strlen(buf),&v) == 1);    assert(v == LONG_MIN);    strcpy(buf,"-2147483649"); /* overflow */    assert(string2l(buf,strlen(buf),&v) == 0);    strcpy(buf,"2147483647");    assert(string2l(buf,strlen(buf),&v) == 1);    assert(v == LONG_MAX);    strcpy(buf,"2147483648"); /* overflow */    assert(string2l(buf,strlen(buf),&v) == 0);#endif}int main(int argc, char **argv) {    test_string2ll();    test_string2l();    return 0;}#endif
0 0
原创粉丝点击