From 321b067a184546850dc25f682c7660264da53f71 Mon Sep 17 00:00:00 2001 From: Michael Friedrich Date: Thu, 9 Mar 2017 12:26:09 +0100 Subject: [PATCH] Use hiredis 0.13.3 refs #4991 --- third-party/hiredis/.travis.yml | 15 - third-party/hiredis/CHANGELOG.md | 39 -- third-party/hiredis/Makefile | 4 +- third-party/hiredis/README.md | 27 +- third-party/hiredis/adapters/libevent.h | 24 +- third-party/hiredis/adapters/libuv.h | 5 +- third-party/hiredis/appveyor.yml | 36 -- third-party/hiredis/async.c | 2 +- third-party/hiredis/dict.c | 4 +- third-party/hiredis/examples/example.c | 2 +- third-party/hiredis/fmacros.h | 12 +- third-party/hiredis/hiredis.c | 8 +- third-party/hiredis/hiredis.h | 10 +- third-party/hiredis/net.c | 43 +- third-party/hiredis/read.c | 2 +- third-party/hiredis/read.h | 13 +- third-party/hiredis/sds.c | 507 ++++++++---------------- third-party/hiredis/sds.h | 200 +--------- third-party/hiredis/sdsalloc.h | 42 -- third-party/hiredis/test.c | 44 +- 20 files changed, 254 insertions(+), 785 deletions(-) delete mode 100644 third-party/hiredis/appveyor.yml delete mode 100644 third-party/hiredis/sdsalloc.h diff --git a/third-party/hiredis/.travis.yml b/third-party/hiredis/.travis.yml index ad08076d8..1e1ce3006 100644 --- a/third-party/hiredis/.travis.yml +++ b/third-party/hiredis/.travis.yml @@ -4,13 +4,6 @@ compiler: - gcc - clang -os: - - linux - - osx - -before_script: - - if [ "$TRAVIS_OS_NAME" == "osx" ] ; then brew update; brew install redis; fi - addons: apt: packages: @@ -28,12 +21,4 @@ env: - TARGET="32bit" TARGET_VARS="32bit-vars" CFLAGS="-Werror" - TARGET="32bit" TARGET_VARS="32bit-vars" PRE="valgrind --track-origins=yes --leak-check=full" -matrix: - exclude: - - os: osx - env: PRE="valgrind --track-origins=yes --leak-check=full" - - - os: osx - env: TARGET="32bit" TARGET_VARS="32bit-vars" PRE="valgrind --track-origins=yes --leak-check=full" - script: make $TARGET CFLAGS="$CFLAGS" && make check PRE="$PRE" && make $TARGET_VARS hiredis-example diff --git a/third-party/hiredis/CHANGELOG.md b/third-party/hiredis/CHANGELOG.md index f92bcb3c9..a5015c5da 100644 --- a/third-party/hiredis/CHANGELOG.md +++ b/third-party/hiredis/CHANGELOG.md @@ -1,42 +1,3 @@ -### 1.0.0 (unreleased) - -**Fixes**: - -* Catch a buffer overflow when formatting the error message -* Import latest upstream sds. This breaks applications that are linked against the old hiredis v0.13 -* Fix warnings, when compiled with -Wshadow -* Make hiredis compile in Cygwin on Windows, now CI-tested - -**BREAKING CHANGES**: - -* Change `redisReply.len` to `size_t`, as it denotes the the size of a string - -User code should compare this to `size_t` values as well. -If it was used to compare to other values, casting might be necessary or can be removed, if casting was applied before. - -* Remove backwards compatibility macro's - -This removes the following old function aliases, use the new name now: - -| Old | New | -| --------------------------- | ---------------------- | -| redisReplyReaderCreate | redisReaderCreate | -| redisReplyReaderCreate | redisReaderCreate | -| redisReplyReaderFree | redisReaderFree | -| redisReplyReaderFeed | redisReaderFeed | -| redisReplyReaderGetReply | redisReaderGetReply | -| redisReplyReaderSetPrivdata | redisReaderSetPrivdata | -| redisReplyReaderGetObject | redisReaderGetObject | -| redisReplyReaderGetError | redisReaderGetError | - -* The `DEBUG` variable in the Makefile was renamed to `DEBUG_FLAGS` - -Previously it broke some builds for people that had `DEBUG` set to some arbitrary value, -due to debugging other software. -By renaming we avoid unintentional name clashes. - -Simply rename `DEBUG` to `DEBUG_FLAGS` in your environment to make it working again. - ### 0.13.3 (2015-09-16) * Revert "Clear `REDIS_CONNECTED` flag when connection is closed". diff --git a/third-party/hiredis/Makefile b/third-party/hiredis/Makefile index 9a4de8360..cff2a84ce 100644 --- a/third-party/hiredis/Makefile +++ b/third-party/hiredis/Makefile @@ -40,8 +40,8 @@ CC:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo $(CC) || echo gcc') CXX:=$(shell sh -c 'type $(CXX) >/dev/null 2>/dev/null && echo $(CXX) || echo g++') OPTIMIZATION?=-O3 WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings -DEBUG_FLAGS?= -g -ggdb -REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG_FLAGS) $(ARCH) +DEBUG?= -g -ggdb +REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG) $(ARCH) REAL_LDFLAGS=$(LDFLAGS) $(ARCH) DYLIBSUFFIX=so diff --git a/third-party/hiredis/README.md b/third-party/hiredis/README.md index 01223ea59..4f1a58d2a 100644 --- a/third-party/hiredis/README.md +++ b/third-party/hiredis/README.md @@ -1,7 +1,5 @@ [![Build Status](https://travis-ci.org/redis/hiredis.png)](https://travis-ci.org/redis/hiredis) -**This Readme reflects the latest changed in the master branch. See [v0.13.3](https://github.com/redis/hiredis/tree/v0.13.3) for the Readme and documentation for the latest release.** - # HIREDIS Hiredis is a minimalistic C client library for the [Redis](http://redis.io/) database. @@ -22,15 +20,7 @@ Redis version >= 1.2.0. The library comes with multiple APIs. There is the *synchronous API*, the *asynchronous API* and the *reply parsing API*. -## Upgrading to `1.0.0` - -Version 1.0.0 marks a stable release of hiredis. -It includes some minor breaking changes, mostly to make the exposed API more uniform and self-explanatory. -It also bundles the updated `sds` library, to sync up with upstream and Redis. -For most applications a recompile against the new hiredis should be enough. -For code changes see the [Changelog](CHANGELOG.md). - -## Upgrading from `<0.9.0` +## UPGRADING Version 0.9.0 is a major overhaul of hiredis in every aspect. However, upgrading existing code using hiredis should not be a big pain. The key thing to keep in mind when @@ -58,18 +48,12 @@ After trying to connect to Redis using `redisConnect` you should check the `err` field to see if establishing the connection was successful: ```c redisContext *c = redisConnect("127.0.0.1", 6379); -if (c == NULL || c->err) { - if (c) { - printf("Error: %s\n", c->errstr); - // handle error - } else { - printf("Can't allocate redis context\n"); - } +if (c != NULL && c->err) { + printf("Error: %s\n", c->errstr); + // handle error } ``` -*Note: A `redisContext` is not thread-safe.* - ### Sending commands There are several ways to issue commands to Redis. The first that will be introduced is @@ -257,9 +241,6 @@ Redis. It returns a pointer to the newly created `redisAsyncContext` struct. The should be checked after creation to see if there were errors creating the connection. Because the connection that will be created is non-blocking, the kernel is not able to instantly return if the specified host and port is able to accept a connection. - -*Note: A `redisAsyncContext` is not thread-safe.* - ```c redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); if (c->err) { diff --git a/third-party/hiredis/adapters/libevent.h b/third-party/hiredis/adapters/libevent.h index 273d8b2dd..1c2b271bb 100644 --- a/third-party/hiredis/adapters/libevent.h +++ b/third-party/hiredis/adapters/libevent.h @@ -30,13 +30,13 @@ #ifndef __HIREDIS_LIBEVENT_H__ #define __HIREDIS_LIBEVENT_H__ -#include +#include #include "../hiredis.h" #include "../async.h" typedef struct redisLibeventEvents { redisAsyncContext *context; - struct event *rev, *wev; + struct event rev, wev; } redisLibeventEvents; static void redisLibeventReadEvent(int fd, short event, void *arg) { @@ -53,28 +53,28 @@ static void redisLibeventWriteEvent(int fd, short event, void *arg) { static void redisLibeventAddRead(void *privdata) { redisLibeventEvents *e = (redisLibeventEvents*)privdata; - event_add(e->rev,NULL); + event_add(&e->rev,NULL); } static void redisLibeventDelRead(void *privdata) { redisLibeventEvents *e = (redisLibeventEvents*)privdata; - event_del(e->rev); + event_del(&e->rev); } static void redisLibeventAddWrite(void *privdata) { redisLibeventEvents *e = (redisLibeventEvents*)privdata; - event_add(e->wev,NULL); + event_add(&e->wev,NULL); } static void redisLibeventDelWrite(void *privdata) { redisLibeventEvents *e = (redisLibeventEvents*)privdata; - event_del(e->wev); + event_del(&e->wev); } static void redisLibeventCleanup(void *privdata) { redisLibeventEvents *e = (redisLibeventEvents*)privdata; - event_del(e->rev); - event_del(e->wev); + event_del(&e->rev); + event_del(&e->wev); free(e); } @@ -99,10 +99,10 @@ static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) { ac->ev.data = e; /* Initialize and install read/write events */ - e->rev = event_new(base, c->fd, EV_READ, redisLibeventReadEvent, e); - e->wev = event_new(base, c->fd, EV_WRITE, redisLibeventWriteEvent, e); - event_add(e->rev, NULL); - event_add(e->wev, NULL); + event_set(&e->rev,c->fd,EV_READ,redisLibeventReadEvent,e); + event_set(&e->wev,c->fd,EV_WRITE,redisLibeventWriteEvent,e); + event_base_set(base,&e->rev); + event_base_set(base,&e->wev); return REDIS_OK; } #endif diff --git a/third-party/hiredis/adapters/libuv.h b/third-party/hiredis/adapters/libuv.h index ff08c25e1..3cdf3d394 100644 --- a/third-party/hiredis/adapters/libuv.h +++ b/third-party/hiredis/adapters/libuv.h @@ -20,10 +20,10 @@ static void redisLibuvPoll(uv_poll_t* handle, int status, int events) { return; } - if (p->context != NULL && (events & UV_READABLE)) { + if (events & UV_READABLE) { redisAsyncHandleRead(p->context); } - if (p->context != NULL && (events & UV_WRITABLE)) { + if (events & UV_WRITABLE) { redisAsyncHandleWrite(p->context); } } @@ -83,7 +83,6 @@ static void on_close(uv_handle_t* handle) { static void redisLibuvCleanup(void *privdata) { redisLibuvEvents* p = (redisLibuvEvents*)privdata; - p->context = NULL; // indicate that context might no longer exist uv_close((uv_handle_t*)&p->handle, on_close); } diff --git a/third-party/hiredis/appveyor.yml b/third-party/hiredis/appveyor.yml deleted file mode 100644 index 06bbef117..000000000 --- a/third-party/hiredis/appveyor.yml +++ /dev/null @@ -1,36 +0,0 @@ -# Appveyor configuration file for CI build of hiredis on Windows (under Cygwin) -environment: - matrix: - - CYG_ROOT: C:\cygwin64 - CYG_SETUP: setup-x86_64.exe - CYG_MIRROR: http://cygwin.mirror.constant.com - CYG_CACHE: C:\cygwin64\var\cache\setup - CYG_BASH: C:\cygwin64\bin\bash - CC: gcc - - CYG_ROOT: C:\cygwin - CYG_SETUP: setup-x86.exe - CYG_MIRROR: http://cygwin.mirror.constant.com - CYG_CACHE: C:\cygwin\var\cache\setup - CYG_BASH: C:\cygwin\bin\bash - CC: gcc - TARGET: 32bit - TARGET_VARS: 32bit-vars - -# Cache Cygwin files to speed up build -cache: - - '%CYG_CACHE%' -clone_depth: 1 - -# Attempt to ensure we don't try to convert line endings to Win32 CRLF as this will cause build to fail -init: - - git config --global core.autocrlf input - -# Install needed build dependencies -install: - - ps: 'Start-FileDownload "http://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP"' - - '%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages automake,bison,gcc-core,libtool,make,gettext-devel,gettext,intltool,pkg-config,clang,llvm > NUL 2>&1' - - '%CYG_BASH% -lc "cygcheck -dc cygwin"' - -build_script: - - 'echo building...' - - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0c); diff --git a/third-party/hiredis/dict.c b/third-party/hiredis/dict.c index e17a62546..79b1041ca 100644 --- a/third-party/hiredis/dict.c +++ b/third-party/hiredis/dict.c @@ -161,7 +161,7 @@ static int dictReplace(dict *ht, void *key, void *val) { dictEntry *entry, auxentry; /* Try to add the element. If the key - * does not exists dictAdd will succeed. */ + * does not exists dictAdd will suceed. */ if (dictAdd(ht, key, val) == DICT_OK) return 1; /* It already exists, get the entry */ @@ -293,7 +293,7 @@ static void dictReleaseIterator(dictIterator *iter) { /* Expand the hash table if needed */ static int _dictExpandIfNeeded(dict *ht) { - /* If the hash table is empty expand it to the initial size, + /* If the hash table is empty expand it to the intial size, * if the table is "full" dobule its size. */ if (ht->size == 0) return dictExpand(ht, DICT_HT_INITIAL_SIZE); diff --git a/third-party/hiredis/examples/example.c b/third-party/hiredis/examples/example.c index 4d494c55a..25226a807 100644 --- a/third-party/hiredis/examples/example.c +++ b/third-party/hiredis/examples/example.c @@ -57,7 +57,7 @@ int main(int argc, char **argv) { for (j = 0; j < 10; j++) { char buf[64]; - snprintf(buf,64,"%u",j); + snprintf(buf,64,"%d",j); reply = redisCommand(c,"LPUSH mylist element-%s", buf); freeReplyObject(reply); } diff --git a/third-party/hiredis/fmacros.h b/third-party/hiredis/fmacros.h index 14fed6060..19d7b2193 100644 --- a/third-party/hiredis/fmacros.h +++ b/third-party/hiredis/fmacros.h @@ -6,19 +6,15 @@ #define _DEFAULT_SOURCE #endif -#if defined(__CYGWIN__) -#include -#endif - #if defined(__sun__) #define _POSIX_C_SOURCE 200112L -#else -#if !(defined(__APPLE__) && defined(__MACH__)) +#elif defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) #define _XOPEN_SOURCE 600 -#endif +#else +#define _XOPEN_SOURCE #endif -#if defined(__APPLE__) && defined(__MACH__) +#if __APPLE__ && __MACH__ #define _OSX #endif diff --git a/third-party/hiredis/hiredis.c b/third-party/hiredis/hiredis.c index 18bdfc99c..73d0251bc 100644 --- a/third-party/hiredis/hiredis.c +++ b/third-party/hiredis/hiredis.c @@ -507,7 +507,7 @@ int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv, cmd = sdscatfmt(cmd, "*%i\r\n", argc); for (j=0; j < argc; j++) { len = argvlen ? argvlen[j] : strlen(argv[j]); - cmd = sdscatfmt(cmd, "$%u\r\n", len); + cmd = sdscatfmt(cmd, "$%T\r\n", len); cmd = sdscatlen(cmd, argv[j], len); cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1); } @@ -822,10 +822,10 @@ int redisBufferRead(redisContext *c) { /* Write the output buffer to the socket. * * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was - * successfully written to the socket. When the buffer is empty after the + * succesfully written to the socket. When the buffer is empty after the * write operation, "done" is set to 1 (if given). * - * Returns REDIS_ERR if an error occurred trying to write and sets + * Returns REDIS_ERR if an error occured trying to write and sets * c->errstr to hold the appropriate error string. */ int redisBufferWrite(redisContext *c, int *done) { @@ -984,7 +984,7 @@ int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const s * context is non-blocking, the "reply" pointer will not be used and the * command is simply appended to the write buffer. * - * Returns the reply when a reply was successfully retrieved. Returns NULL + * Returns the reply when a reply was succesfully retrieved. Returns NULL * otherwise. When NULL is returned in a blocking context, the error field * in the context will be set. */ diff --git a/third-party/hiredis/hiredis.h b/third-party/hiredis/hiredis.h index 423d5e504..fe267b9b3 100644 --- a/third-party/hiredis/hiredis.h +++ b/third-party/hiredis/hiredis.h @@ -98,8 +98,8 @@ * then GNU strerror_r returned an internal static buffer and we \ * need to copy the result into our private buffer. */ \ if (err_str != (buf)) { \ - strncpy((buf), err_str, ((len) - 1)); \ - buf[(len)-1] = '\0'; \ + buf[(len)] = '\0'; \ + strncat((buf), err_str, ((len) - 1)); \ } \ } while (0) #endif @@ -112,7 +112,7 @@ extern "C" { typedef struct redisReply { int type; /* REDIS_REPLY_* */ long long integer; /* The integer when type is REDIS_REPLY_INTEGER */ - size_t len; /* Length of string */ + int len; /* Length of string */ char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */ size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */ struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */ @@ -133,7 +133,7 @@ void redisFreeSdsCommand(sds cmd); enum redisConnectionType { REDIS_CONN_TCP, - REDIS_CONN_UNIX + REDIS_CONN_UNIX, }; /* Context for a connection to Redis */ @@ -179,7 +179,7 @@ redisContext *redisConnectFd(int fd); * host, ip (or path), timeout and bind address are reused, * flags are used unmodified from the existing context. * - * Returns REDIS_OK on successful connect or REDIS_ERR otherwise. + * Returns REDIS_OK on successfull connect or REDIS_ERR otherwise. */ int redisReconnect(redisContext *c); diff --git a/third-party/hiredis/net.c b/third-party/hiredis/net.c index 024f645b1..60a2dc754 100644 --- a/third-party/hiredis/net.c +++ b/third-party/hiredis/net.c @@ -65,13 +65,12 @@ static void redisContextCloseFd(redisContext *c) { } static void __redisSetErrorFromErrno(redisContext *c, int type, const char *prefix) { - int errorno = errno; /* snprintf() may change errno */ char buf[128] = { 0 }; size_t len = 0; if (prefix != NULL) len = snprintf(buf,sizeof(buf),"%s: ",prefix); - __redis_strerror_r(errorno, (char *)(buf + len), sizeof(buf) - len); + __redis_strerror_r(errno, (char *)(buf + len), sizeof(buf) - len); __redisSetError(c,type,buf); } @@ -179,15 +178,19 @@ static int redisSetTcpNoDelay(redisContext *c) { #define __MAX_MSEC (((LONG_MAX) - 999) / 1000) -static int redisContextTimeoutMsec(redisContext *c, long *result) -{ - const struct timeval *timeout = c->timeout; - long msec = -1; +static int redisContextWaitReady(redisContext *c, const struct timeval *timeout) { + struct pollfd wfd[1]; + long msec; + + msec = -1; + wfd[0].fd = c->fd; + wfd[0].events = POLLOUT; /* Only use timeout when not NULL. */ if (timeout != NULL) { if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) { - *result = msec; + __redisSetErrorFromErrno(c, REDIS_ERR_IO, NULL); + redisContextCloseFd(c); return REDIS_ERR; } @@ -198,16 +201,6 @@ static int redisContextTimeoutMsec(redisContext *c, long *result) } } - *result = msec; - return REDIS_OK; -} - -static int redisContextWaitReady(redisContext *c, long msec) { - struct pollfd wfd[1]; - - wfd[0].fd = c->fd; - wfd[0].events = POLLOUT; - if (errno == EINPROGRESS) { int res; @@ -272,9 +265,7 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port, int blocking = (c->flags & REDIS_BLOCK); int reuseaddr = (c->flags & REDIS_REUSEADDR); int reuses = 0; - long timeout_msec = -1; - servinfo = NULL; c->connection_type = REDIS_CONN_TCP; c->tcp.port = port; @@ -305,11 +296,6 @@ static int _redisContextConnectTcp(redisContext *c, const char *addr, int port, c->timeout = NULL; } - if (redisContextTimeoutMsec(c, &timeout_msec) != REDIS_OK) { - __redisSetError(c, REDIS_ERR_IO, "Invalid timeout specified"); - goto error; - } - if (source_addr == NULL) { free(c->tcp.source_addr); c->tcp.source_addr = NULL; @@ -385,11 +371,10 @@ addrretry: if (++reuses >= REDIS_CONNECT_RETRIES) { goto error; } else { - redisContextCloseFd(c); goto addrretry; } } else { - if (redisContextWaitReady(c,timeout_msec) != REDIS_OK) + if (redisContextWaitReady(c,c->timeout) != REDIS_OK) goto error; } } @@ -430,7 +415,6 @@ int redisContextConnectBindTcp(redisContext *c, const char *addr, int port, int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout) { int blocking = (c->flags & REDIS_BLOCK); struct sockaddr_un sa; - long timeout_msec = -1; if (redisCreateSocket(c,AF_LOCAL) < 0) return REDIS_ERR; @@ -454,16 +438,13 @@ int redisContextConnectUnix(redisContext *c, const char *path, const struct time c->timeout = NULL; } - if (redisContextTimeoutMsec(c,&timeout_msec) != REDIS_OK) - return REDIS_ERR; - sa.sun_family = AF_LOCAL; strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1); if (connect(c->fd, (struct sockaddr*)&sa, sizeof(sa)) == -1) { if (errno == EINPROGRESS && !blocking) { /* This is ok. */ } else { - if (redisContextWaitReady(c,timeout_msec) != REDIS_OK) + if (redisContextWaitReady(c,c->timeout) != REDIS_OK) return REDIS_ERR; } } diff --git a/third-party/hiredis/read.c b/third-party/hiredis/read.c index 50333b534..df1a467a9 100644 --- a/third-party/hiredis/read.c +++ b/third-party/hiredis/read.c @@ -127,7 +127,7 @@ static char *seekNewline(char *s, size_t len) { * might not have a trailing NULL character. */ while (pos < _len) { while(pos < _len && s[pos] != '\r') pos++; - if (pos==_len) { + if (s[pos] != '\r') { /* Not found. */ return NULL; } else { diff --git a/third-party/hiredis/read.h b/third-party/hiredis/read.h index 2988aa453..635a872cd 100644 --- a/third-party/hiredis/read.h +++ b/third-party/hiredis/read.h @@ -38,7 +38,7 @@ #define REDIS_OK 0 /* When an error occurs, the err flag in a context is set to hold the type of - * error that occurred. REDIS_ERR_IO means there was an I/O error and you + * error that occured. REDIS_ERR_IO means there was an I/O error and you * should use the "errno" variable to find out what is wrong. * For other values, the "errstr" field will hold a description. */ #define REDIS_ERR_IO 1 /* Error in read or write */ @@ -100,9 +100,14 @@ void redisReaderFree(redisReader *r); int redisReaderFeed(redisReader *r, const char *buf, size_t len); int redisReaderGetReply(redisReader *r, void **reply); -#define redisReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p)) -#define redisReaderGetObject(_r) (((redisReader*)(_r))->reply) -#define redisReaderGetError(_r) (((redisReader*)(_r))->errstr) +/* Backwards compatibility, can be removed on big version bump. */ +#define redisReplyReaderCreate redisReaderCreate +#define redisReplyReaderFree redisReaderFree +#define redisReplyReaderFeed redisReaderFeed +#define redisReplyReaderGetReply redisReaderGetReply +#define redisReplyReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p)) +#define redisReplyReaderGetObject(_r) (((redisReader*)(_r))->reply) +#define redisReplyReaderGetError(_r) (((redisReader*)(_r))->errstr) #ifdef __cplusplus } diff --git a/third-party/hiredis/sds.c b/third-party/hiredis/sds.c index 923ffd82f..5d55b7792 100644 --- a/third-party/hiredis/sds.c +++ b/third-party/hiredis/sds.c @@ -1,8 +1,6 @@ -/* SDSLib 2.0 -- A C dynamic strings library +/* SDS (Simple Dynamic Strings), A C dynamic strings library. * - * Copyright (c) 2006-2015, Salvatore Sanfilippo - * Copyright (c) 2015, Oran Agra - * Copyright (c) 2015, Redis Labs, Inc + * Copyright (c) 2006-2014, Salvatore Sanfilippo * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,36 +33,8 @@ #include #include #include -#include "sds.h" -#include "sdsalloc.h" - -static inline int sdsHdrSize(char type) { - switch(type&SDS_TYPE_MASK) { - case SDS_TYPE_5: - return sizeof(struct sdshdr5); - case SDS_TYPE_8: - return sizeof(struct sdshdr8); - case SDS_TYPE_16: - return sizeof(struct sdshdr16); - case SDS_TYPE_32: - return sizeof(struct sdshdr32); - case SDS_TYPE_64: - return sizeof(struct sdshdr64); - } - return 0; -} -static inline char sdsReqType(size_t string_size) { - if (string_size < 32) - return SDS_TYPE_5; - if (string_size < 0xff) - return SDS_TYPE_8; - if (string_size < 0xffff) - return SDS_TYPE_16; - if (string_size < 0xffffffff) - return SDS_TYPE_32; - return SDS_TYPE_64; -} +#include "sds.h" /* Create a new sds string with the content specified by the 'init' pointer * and 'initlen'. @@ -73,65 +43,26 @@ static inline char sdsReqType(size_t string_size) { * The string is always null-termined (all the sds strings are, always) so * even if you create an sds string with: * - * mystring = sdsnewlen("abc",3); + * mystring = sdsnewlen("abc",3"); * * You can print the string with printf() as there is an implicit \0 at the * end of the string. However the string is binary safe and can contain * \0 characters in the middle, as the length is stored in the sds header. */ sds sdsnewlen(const void *init, size_t initlen) { - void *sh; - sds s; - char type = sdsReqType(initlen); - /* Empty strings are usually created in order to append. Use type 8 - * since type 5 is not good at this. */ - if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8; - int hdrlen = sdsHdrSize(type); - unsigned char *fp; /* flags pointer. */ - - sh = s_malloc(hdrlen+initlen+1); - if (sh == NULL) return NULL; - if (!init) - memset(sh, 0, hdrlen+initlen+1); - s = (char*)sh+hdrlen; - fp = ((unsigned char*)s)-1; - switch(type) { - case SDS_TYPE_5: { - *fp = type | (initlen << SDS_TYPE_BITS); - break; - } - case SDS_TYPE_8: { - SDS_HDR_VAR(8,s); - sh->len = initlen; - sh->alloc = initlen; - *fp = type; - break; - } - case SDS_TYPE_16: { - SDS_HDR_VAR(16,s); - sh->len = initlen; - sh->alloc = initlen; - *fp = type; - break; - } - case SDS_TYPE_32: { - SDS_HDR_VAR(32,s); - sh->len = initlen; - sh->alloc = initlen; - *fp = type; - break; - } - case SDS_TYPE_64: { - SDS_HDR_VAR(64,s); - sh->len = initlen; - sh->alloc = initlen; - *fp = type; - break; - } + struct sdshdr *sh; + + if (init) { + sh = malloc(sizeof *sh+initlen+1); + } else { + sh = calloc(sizeof *sh+initlen+1,1); } + if (sh == NULL) return NULL; + sh->len = initlen; + sh->free = 0; if (initlen && init) - memcpy(s, init, initlen); - s[initlen] = '\0'; - return s; + memcpy(sh->buf, init, initlen); + sh->buf[initlen] = '\0'; + return (char*)sh->buf; } /* Create an empty (zero length) sds string. Even in this case the string @@ -140,7 +71,7 @@ sds sdsempty(void) { return sdsnewlen("",0); } -/* Create a new sds string starting from a null terminated C string. */ +/* Create a new sds string starting from a null termined C string. */ sds sdsnew(const char *init) { size_t initlen = (init == NULL) ? 0 : strlen(init); return sdsnewlen(init, initlen); @@ -154,7 +85,7 @@ sds sdsdup(const sds s) { /* Free an sds string. No operation is performed if 's' is NULL. */ void sdsfree(sds s) { if (s == NULL) return; - s_free((char*)s-sdsHdrSize(s[-1])); + free(s-sizeof(struct sdshdr)); } /* Set the sds string length to the length as obtained with strlen(), so @@ -172,17 +103,21 @@ void sdsfree(sds s) { * the output will be "6" as the string was modified but the logical length * remains 6 bytes. */ void sdsupdatelen(sds s) { + struct sdshdr *sh = (void*) (s-sizeof *sh); int reallen = strlen(s); - sdssetlen(s, reallen); + sh->free += (sh->len-reallen); + sh->len = reallen; } -/* Modify an sds string in-place to make it empty (zero length). +/* Modify an sds string on-place to make it empty (zero length). * However all the existing buffer is not discarded but set as free space * so that next append operations will not require allocations up to the * number of bytes previously available. */ void sdsclear(sds s) { - sdssetlen(s, 0); - s[0] = '\0'; + struct sdshdr *sh = (void*) (s-sizeof *sh); + sh->free += sh->len; + sh->len = 0; + sh->buf[0] = '\0'; } /* Enlarge the free space at the end of the sds string so that the caller @@ -192,48 +127,23 @@ void sdsclear(sds s) { * Note: this does not change the *length* of the sds string as returned * by sdslen(), but only the free buffer space we have. */ sds sdsMakeRoomFor(sds s, size_t addlen) { - void *sh, *newsh; - size_t avail = sdsavail(s); + struct sdshdr *sh, *newsh; + size_t free = sdsavail(s); size_t len, newlen; - char type, oldtype = s[-1] & SDS_TYPE_MASK; - int hdrlen; - - /* Return ASAP if there is enough space left. */ - if (avail >= addlen) return s; + if (free >= addlen) return s; len = sdslen(s); - sh = (char*)s-sdsHdrSize(oldtype); + sh = (void*) (s-sizeof *sh); newlen = (len+addlen); if (newlen < SDS_MAX_PREALLOC) newlen *= 2; else newlen += SDS_MAX_PREALLOC; + newsh = realloc(sh, sizeof *newsh+newlen+1); + if (newsh == NULL) return NULL; - type = sdsReqType(newlen); - - /* Don't use type 5: the user is appending to the string and type 5 is - * not able to remember empty space, so sdsMakeRoomFor() must be called - * at every appending operation. */ - if (type == SDS_TYPE_5) type = SDS_TYPE_8; - - hdrlen = sdsHdrSize(type); - if (oldtype==type) { - newsh = s_realloc(sh, hdrlen+newlen+1); - if (newsh == NULL) return NULL; - s = (char*)newsh+hdrlen; - } else { - /* Since the header size changes, need to move the string forward, - * and can't use realloc */ - newsh = s_malloc(hdrlen+newlen+1); - if (newsh == NULL) return NULL; - memcpy((char*)newsh+hdrlen, s, len+1); - s_free(sh); - s = (char*)newsh+hdrlen; - s[-1] = type; - sdssetlen(s, len); - } - sdssetalloc(s, newlen); - return s; + newsh->free = newlen - len; + return newsh->buf; } /* Reallocate the sds string so that it has no free space at the end. The @@ -243,29 +153,12 @@ sds sdsMakeRoomFor(sds s, size_t addlen) { * After the call, the passed sds string is no longer valid and all the * references must be substituted with the new pointer returned by the call. */ sds sdsRemoveFreeSpace(sds s) { - void *sh, *newsh; - char type, oldtype = s[-1] & SDS_TYPE_MASK; - int hdrlen; - size_t len = sdslen(s); - sh = (char*)s-sdsHdrSize(oldtype); - - type = sdsReqType(len); - hdrlen = sdsHdrSize(type); - if (oldtype==type) { - newsh = s_realloc(sh, hdrlen+len+1); - if (newsh == NULL) return NULL; - s = (char*)newsh+hdrlen; - } else { - newsh = s_malloc(hdrlen+len+1); - if (newsh == NULL) return NULL; - memcpy((char*)newsh+hdrlen, s, len+1); - s_free(sh); - s = (char*)newsh+hdrlen; - s[-1] = type; - sdssetlen(s, len); - } - sdssetalloc(s, len); - return s; + struct sdshdr *sh; + + sh = (void*) (s-sizeof *sh); + sh = realloc(sh, sizeof *sh+sh->len+1); + sh->free = 0; + return sh->buf; } /* Return the total size of the allocation of the specifed sds string, @@ -276,14 +169,9 @@ sds sdsRemoveFreeSpace(sds s) { * 4) The implicit null term. */ size_t sdsAllocSize(sds s) { - size_t alloc = sdsalloc(s); - return sdsHdrSize(s[-1])+alloc+1; -} + struct sdshdr *sh = (void*) (s-sizeof *sh); -/* Return the pointer of the actual SDS allocation (normally SDS strings - * are referenced by the start of the string buffer). */ -void *sdsAllocPtr(sds s) { - return (void*) (s-sdsHdrSize(s[-1])); + return sizeof(*sh)+sh->len+sh->free+1; } /* Increment the sds length and decrements the left free space at the @@ -310,44 +198,13 @@ void *sdsAllocPtr(sds s) { * sdsIncrLen(s, nread); */ void sdsIncrLen(sds s, int incr) { - unsigned char flags = s[-1]; - size_t len; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: { - unsigned char *fp = ((unsigned char*)s)-1; - unsigned char oldlen = SDS_TYPE_5_LEN(flags); - assert((incr > 0 && oldlen+incr < 32) || (incr < 0 && oldlen >= (unsigned int)(-incr))); - *fp = SDS_TYPE_5 | ((oldlen+incr) << SDS_TYPE_BITS); - len = oldlen+incr; - break; - } - case SDS_TYPE_8: { - SDS_HDR_VAR(8,s); - assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr))); - len = (sh->len += incr); - break; - } - case SDS_TYPE_16: { - SDS_HDR_VAR(16,s); - assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr))); - len = (sh->len += incr); - break; - } - case SDS_TYPE_32: { - SDS_HDR_VAR(32,s); - assert((incr >= 0 && sh->alloc-sh->len >= (unsigned int)incr) || (incr < 0 && sh->len >= (unsigned int)(-incr))); - len = (sh->len += incr); - break; - } - case SDS_TYPE_64: { - SDS_HDR_VAR(64,s); - assert((incr >= 0 && sh->alloc-sh->len >= (uint64_t)incr) || (incr < 0 && sh->len >= (uint64_t)(-incr))); - len = (sh->len += incr); - break; - } - default: len = 0; /* Just to avoid compilation warnings. */ - } - s[len] = '\0'; + struct sdshdr *sh = (void*) (s-sizeof *sh); + + assert(sh->free >= incr); + sh->len += incr; + sh->free -= incr; + assert(sh->free >= 0); + s[sh->len] = '\0'; } /* Grow the sds to have the specified length. Bytes that were not part of @@ -356,15 +213,19 @@ void sdsIncrLen(sds s, int incr) { * if the specified length is smaller than the current length, no operation * is performed. */ sds sdsgrowzero(sds s, size_t len) { - size_t curlen = sdslen(s); + struct sdshdr *sh = (void*) (s-sizeof *sh); + size_t totlen, curlen = sh->len; if (len <= curlen) return s; s = sdsMakeRoomFor(s,len-curlen); if (s == NULL) return NULL; /* Make sure added region doesn't contain garbage */ + sh = (void*)(s-sizeof *sh); memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */ - sdssetlen(s, len); + totlen = sh->len+sh->free; + sh->len = len; + sh->free = totlen-sh->len; return s; } @@ -374,12 +235,15 @@ sds sdsgrowzero(sds s, size_t len) { * After the call, the passed sds string is no longer valid and all the * references must be substituted with the new pointer returned by the call. */ sds sdscatlen(sds s, const void *t, size_t len) { + struct sdshdr *sh; size_t curlen = sdslen(s); s = sdsMakeRoomFor(s,len); if (s == NULL) return NULL; + sh = (void*) (s-sizeof *sh); memcpy(s+curlen, t, len); - sdssetlen(s, curlen+len); + sh->len = curlen+len; + sh->free = sh->free-len; s[curlen+len] = '\0'; return s; } @@ -403,13 +267,19 @@ sds sdscatsds(sds s, const sds t) { /* Destructively modify the sds string 's' to hold the specified binary * safe string pointed by 't' of length 'len' bytes. */ sds sdscpylen(sds s, const char *t, size_t len) { - if (sdsalloc(s) < len) { - s = sdsMakeRoomFor(s,len-sdslen(s)); + struct sdshdr *sh = (void*) (s-sizeof *sh); + size_t totlen = sh->free+sh->len; + + if (totlen < len) { + s = sdsMakeRoomFor(s,len-sh->len); if (s == NULL) return NULL; + sh = (void*) (s-sizeof *sh); + totlen = sh->free+sh->len; } memcpy(s, t, len); s[len] = '\0'; - sdssetlen(s, len); + sh->len = len; + sh->free = totlen-len; return s; } @@ -423,7 +293,7 @@ sds sdscpy(sds s, const char *t) { * conversion. 's' must point to a string with room for at least * SDS_LLSTR_SIZE bytes. * - * The function returns the length of the null-terminated string + * The function returns the lenght of the null-terminated string * representation stored at 's'. */ #define SDS_LLSTR_SIZE 21 int sdsll2str(char *s, long long value) { @@ -486,52 +356,27 @@ int sdsull2str(char *s, unsigned long long v) { return l; } -/* Create an sds string from a long long value. It is much faster than: - * - * sdscatprintf(sdsempty(),"%lld\n", value); - */ -sds sdsfromlonglong(long long value) { - char buf[SDS_LLSTR_SIZE]; - int len = sdsll2str(buf,value); - - return sdsnewlen(buf,len); -} - -/* Like sdscatprintf() but gets va_list instead of being variadic. */ +/* Like sdscatpritf() but gets va_list instead of being variadic. */ sds sdscatvprintf(sds s, const char *fmt, va_list ap) { va_list cpy; - char staticbuf[1024], *buf = staticbuf, *t; - size_t buflen = strlen(fmt)*2; + char *buf, *t; + size_t buflen = 16; - /* We try to start using a static buffer for speed. - * If not possible we revert to heap allocation. */ - if (buflen > sizeof(staticbuf)) { - buf = s_malloc(buflen); - if (buf == NULL) return NULL; - } else { - buflen = sizeof(staticbuf); - } - - /* Try with buffers two times bigger every time we fail to - * fit the string in the current buffer size. */ while(1) { + buf = malloc(buflen); + if (buf == NULL) return NULL; buf[buflen-2] = '\0'; va_copy(cpy,ap); vsnprintf(buf, buflen, fmt, cpy); - va_end(cpy); if (buf[buflen-2] != '\0') { - if (buf != staticbuf) s_free(buf); + free(buf); buflen *= 2; - buf = s_malloc(buflen); - if (buf == NULL) return NULL; continue; } break; } - - /* Finally concat the obtained string to the SDS string and return it. */ t = sdscat(s, buf); - if (buf != staticbuf) s_free(buf); + free(buf); return t; } @@ -544,7 +389,7 @@ sds sdscatvprintf(sds s, const char *fmt, va_list ap) { * Example: * * s = sdsnew("Sum is: "); - * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b). + * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b); * * Often you need to create a string from scratch with the printf-alike * format. When this is the need, just use sdsempty() as the target string: @@ -574,24 +419,29 @@ sds sdscatprintf(sds s, const char *fmt, ...) { * %I - 64 bit signed integer (long long, int64_t) * %u - unsigned int * %U - 64 bit unsigned integer (unsigned long long, uint64_t) + * %T - A size_t variable. * %% - Verbatim "%" character. */ sds sdscatfmt(sds s, char const *fmt, ...) { + struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr))); + size_t initlen = sdslen(s); const char *f = fmt; int i; va_list ap; va_start(ap,fmt); - i = sdslen(s); /* Position of the next byte to write to dest str. */ + f = fmt; /* Next format specifier byte to process. */ + i = initlen; /* Position of the next byte to write to dest str. */ while(*f) { char next, *str; - size_t l; + int l; long long num; unsigned long long unum; /* Make sure there is always space for at least 1 char. */ - if (sdsavail(s)==0) { + if (sh->free == 0) { s = sdsMakeRoomFor(s,1); + sh = (void*) (s-(sizeof(struct sdshdr))); } switch(*f) { @@ -603,11 +453,13 @@ sds sdscatfmt(sds s, char const *fmt, ...) { case 'S': str = va_arg(ap,char*); l = (next == 's') ? strlen(str) : sdslen(str); - if (sdsavail(s) < l) { + if (sh->free < l) { s = sdsMakeRoomFor(s,l); + sh = (void*) (s-(sizeof(struct sdshdr))); } memcpy(s+i,str,l); - sdsinclen(s,l); + sh->len += l; + sh->free -= l; i += l; break; case 'i': @@ -619,40 +471,49 @@ sds sdscatfmt(sds s, char const *fmt, ...) { { char buf[SDS_LLSTR_SIZE]; l = sdsll2str(buf,num); - if (sdsavail(s) < l) { + if (sh->free < l) { s = sdsMakeRoomFor(s,l); + sh = (void*) (s-(sizeof(struct sdshdr))); } memcpy(s+i,buf,l); - sdsinclen(s,l); + sh->len += l; + sh->free -= l; i += l; } break; case 'u': case 'U': + case 'T': if (next == 'u') unum = va_arg(ap,unsigned int); - else + else if(next == 'U') unum = va_arg(ap,unsigned long long); + else + unum = (unsigned long long)va_arg(ap,size_t); { char buf[SDS_LLSTR_SIZE]; l = sdsull2str(buf,unum); - if (sdsavail(s) < l) { + if (sh->free < l) { s = sdsMakeRoomFor(s,l); + sh = (void*) (s-(sizeof(struct sdshdr))); } memcpy(s+i,buf,l); - sdsinclen(s,l); + sh->len += l; + sh->free -= l; i += l; } break; default: /* Handle %% and generally %. */ s[i++] = next; - sdsinclen(s,1); + sh->len += 1; + sh->free -= 1; break; } break; default: s[i++] = *f; - sdsinclen(s,1); + sh->len += 1; + sh->free -= 1; break; } f++; @@ -664,6 +525,7 @@ sds sdscatfmt(sds s, char const *fmt, ...) { return s; } + /* Remove the part of the string from left and from right composed just of * contiguous characters found in 'cset', that is a null terminted C string. * @@ -673,24 +535,25 @@ sds sdscatfmt(sds s, char const *fmt, ...) { * Example: * * s = sdsnew("AA...AA.a.aa.aHelloWorld :::"); - * s = sdstrim(s,"Aa. :"); + * s = sdstrim(s,"A. :"); * printf("%s\n", s); * * Output will be just "Hello World". */ -sds sdstrim(sds s, const char *cset) { +void sdstrim(sds s, const char *cset) { + struct sdshdr *sh = (void*) (s-sizeof *sh); char *start, *end, *sp, *ep; size_t len; sp = start = s; ep = end = s+sdslen(s)-1; while(sp <= end && strchr(cset, *sp)) sp++; - while(ep > sp && strchr(cset, *ep)) ep--; + while(ep > start && strchr(cset, *ep)) ep--; len = (sp > ep) ? 0 : ((ep-sp)+1); - if (s != sp) memmove(s, sp, len); - s[len] = '\0'; - sdssetlen(s,len); - return s; + if (sh->buf != sp) memmove(sh->buf, sp, len); + sh->buf[len] = '\0'; + sh->free = sh->free+(sh->len-len); + sh->len = len; } /* Turn the string into a smaller (or equal) string containing only the @@ -710,6 +573,7 @@ sds sdstrim(sds s, const char *cset) { * sdsrange(s,1,-1); => "ello World" */ void sdsrange(sds s, int start, int end) { + struct sdshdr *sh = (void*) (s-sizeof *sh); size_t newlen, len = sdslen(s); if (len == 0) return; @@ -732,9 +596,10 @@ void sdsrange(sds s, int start, int end) { } else { start = 0; } - if (start && newlen) memmove(s, s+start, newlen); - s[newlen] = 0; - sdssetlen(s,newlen); + if (start && newlen) memmove(sh->buf, sh->buf+start, newlen); + sh->buf[newlen] = 0; + sh->free = sh->free+(sh->len-newlen); + sh->len = newlen; } /* Apply tolower() to every character of the sds string 's'. */ @@ -755,8 +620,8 @@ void sdstoupper(sds s) { * * Return value: * - * positive if s1 > s2. - * negative if s1 < s2. + * 1 if s1 > s2. + * -1 if s1 < s2. * 0 if s1 and s2 are exactly the same binary string. * * If two strings share exactly the same prefix, but one of the two has @@ -796,7 +661,7 @@ sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count if (seplen < 1 || len < 0) return NULL; - tokens = s_malloc(sizeof(sds)*slots); + tokens = malloc(sizeof(sds)*slots); if (tokens == NULL) return NULL; if (len == 0) { @@ -809,7 +674,7 @@ sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count sds *newtokens; slots *= 2; - newtokens = s_realloc(tokens,sizeof(sds)*slots); + newtokens = realloc(tokens,sizeof(sds)*slots); if (newtokens == NULL) goto cleanup; tokens = newtokens; } @@ -833,7 +698,7 @@ cleanup: { int i; for (i = 0; i < elements; i++) sdsfree(tokens[i]); - s_free(tokens); + free(tokens); *count = 0; return NULL; } @@ -844,7 +709,26 @@ void sdsfreesplitres(sds *tokens, int count) { if (!tokens) return; while(count--) sdsfree(tokens[count]); - s_free(tokens); + free(tokens); +} + +/* Create an sds string from a long long value. It is much faster than: + * + * sdscatprintf(sdsempty(),"%lld\n", value); + */ +sds sdsfromlonglong(long long value) { + char buf[32], *p; + unsigned long long v; + + 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++; + return sdsnewlen(p,32-(p-buf)); } /* Append to the sds string "s" an escaped string representation where @@ -1018,13 +902,13 @@ sds *sdssplitargs(const char *line, int *argc) { if (*p) p++; } /* add the token to the vector */ - vector = s_realloc(vector,((*argc)+1)*sizeof(char*)); + vector = realloc(vector,((*argc)+1)*sizeof(char*)); vector[*argc] = current; (*argc)++; current = NULL; } else { /* Even on empty input string return something not NULL. */ - if (vector == NULL) vector = s_malloc(sizeof(void*)); + if (vector == NULL) vector = malloc(sizeof(void*)); return vector; } } @@ -1032,7 +916,7 @@ sds *sdssplitargs(const char *line, int *argc) { err: while((*argc)--) sdsfree(vector[*argc]); - s_free(vector); + free(vector); if (current) sdsfree(current); *argc = 0; return NULL; @@ -1063,13 +947,13 @@ sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) { /* Join an array of C strings using the specified separator (also a C string). * Returns the result as an sds string. */ -sds sdsjoin(char **argv, int argc, char *sep) { +sds sdsjoin(char **argv, int argc, char *sep, size_t seplen) { sds join = sdsempty(); int j; for (j = 0; j < argc; j++) { join = sdscat(join, argv[j]); - if (j != argc-1) join = sdscat(join,sep); + if (j != argc-1) join = sdscatlen(join,sep,seplen); } return join; } @@ -1086,23 +970,13 @@ sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen) { return join; } -/* Wrappers to the allocators used by SDS. Note that SDS will actually - * just use the macros defined into sdsalloc.h in order to avoid to pay - * the overhead of function calls. Here we define these wrappers only for - * the programs SDS is linked to, if they want to touch the SDS internals - * even if they use a different allocator. */ -void *sds_malloc(size_t size) { return s_malloc(size); } -void *sds_realloc(void *ptr, size_t size) { return s_realloc(ptr,size); } -void sds_free(void *ptr) { s_free(ptr); } - -#if defined(SDS_TEST_MAIN) +#ifdef SDS_TEST_MAIN #include #include "testhelp.h" -#include "limits.h" -#define UNUSED(x) (void)(x) -int sdsTest(void) { +int main(void) { { + struct sdshdr *sh; sds x = sdsnew("foo"), y; test_cond("Create a string and obtain the length", @@ -1129,35 +1003,7 @@ int sdsTest(void) { sdsfree(x); x = sdscatprintf(sdsempty(),"%d",123); test_cond("sdscatprintf() seems working in the base case", - sdslen(x) == 3 && memcmp(x,"123\0",4) == 0) - - sdsfree(x); - x = sdsnew("--"); - x = sdscatfmt(x, "Hello %s World %I,%I--", "Hi!", LLONG_MIN,LLONG_MAX); - test_cond("sdscatfmt() seems working in the base case", - sdslen(x) == 60 && - memcmp(x,"--Hello Hi! World -9223372036854775808," - "9223372036854775807--",60) == 0) - printf("[%s]\n",x); - - sdsfree(x); - x = sdsnew("--"); - x = sdscatfmt(x, "%u,%U--", UINT_MAX, ULLONG_MAX); - test_cond("sdscatfmt() seems working with unsigned numbers", - sdslen(x) == 35 && - memcmp(x,"--4294967295,18446744073709551615--",35) == 0) - - sdsfree(x); - x = sdsnew(" x "); - sdstrim(x," x"); - test_cond("sdstrim() works when all chars match", - sdslen(x) == 0) - - sdsfree(x); - x = sdsnew(" x "); - sdstrim(x," "); - test_cond("sdstrim() works when a single char remains", - sdslen(x) == 1 && x[0] == 'x') + sdslen(x) == 3 && memcmp(x,"123\0",4) ==0) sdsfree(x); x = sdsnew("xxciaoyyy"); @@ -1226,47 +1072,24 @@ int sdsTest(void) { memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0) { - unsigned int oldfree; - char *p; - int step = 10, j, i; + int oldfree; sdsfree(x); - sdsfree(y); x = sdsnew("0"); - test_cond("sdsnew() free/len buffers", sdslen(x) == 1 && sdsavail(x) == 0); - - /* Run the test a few times in order to hit the first two - * SDS header types. */ - for (i = 0; i < 10; i++) { - int oldlen = sdslen(x); - x = sdsMakeRoomFor(x,step); - int type = x[-1]&SDS_TYPE_MASK; - - test_cond("sdsMakeRoomFor() len", sdslen(x) == oldlen); - if (type != SDS_TYPE_5) { - test_cond("sdsMakeRoomFor() free", sdsavail(x) >= step); - oldfree = sdsavail(x); - } - p = x+oldlen; - for (j = 0; j < step; j++) { - p[j] = 'A'+j; - } - sdsIncrLen(x,step); - } - test_cond("sdsMakeRoomFor() content", - memcmp("0ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ",x,101) == 0); - test_cond("sdsMakeRoomFor() final length",sdslen(x)==101); - - sdsfree(x); + sh = (void*) (x-(sizeof(struct sdshdr))); + test_cond("sdsnew() free/len buffers", sh->len == 1 && sh->free == 0); + x = sdsMakeRoomFor(x,1); + sh = (void*) (x-(sizeof(struct sdshdr))); + test_cond("sdsMakeRoomFor()", sh->len == 1 && sh->free > 0); + oldfree = sh->free; + x[1] = '1'; + sdsIncrLen(x,1); + test_cond("sdsIncrLen() -- content", x[0] == '0' && x[1] == '1'); + test_cond("sdsIncrLen() -- len", sh->len == 2); + test_cond("sdsIncrLen() -- free", sh->free == oldfree-1); } } test_report() return 0; } #endif - -#ifdef SDS_TEST_MAIN -int main(void) { - return sdsTest(); -} -#endif diff --git a/third-party/hiredis/sds.h b/third-party/hiredis/sds.h index 13be75a9f..19a2abd31 100644 --- a/third-party/hiredis/sds.h +++ b/third-party/hiredis/sds.h @@ -1,8 +1,6 @@ -/* SDSLib 2.0 -- A C dynamic strings library +/* SDS (Simple Dynamic Strings), A C dynamic strings library. * - * Copyright (c) 2006-2015, Salvatore Sanfilippo - * Copyright (c) 2015, Oran Agra - * Copyright (c) 2015, Redis Labs, Inc + * Copyright (c) 2006-2014, Salvatore Sanfilippo * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,188 +35,35 @@ #include #include -#include +#ifdef _MSC_VER +#include "win32.h" +#endif typedef char *sds; -/* Note: sdshdr5 is never used, we just access the flags byte directly. - * However is here to document the layout of type 5 SDS strings. */ -struct __attribute__ ((__packed__)) sdshdr5 { - unsigned char flags; /* 3 lsb of type, and 5 msb of string length */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr8 { - uint8_t len; /* used */ - uint8_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr16 { - uint16_t len; /* used */ - uint16_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr32 { - uint32_t len; /* used */ - uint32_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ - char buf[]; -}; -struct __attribute__ ((__packed__)) sdshdr64 { - uint64_t len; /* used */ - uint64_t alloc; /* excluding the header and null terminator */ - unsigned char flags; /* 3 lsb of type, 5 unused bits */ +struct sdshdr { + int len; + int free; char buf[]; }; -#define SDS_TYPE_5 0 -#define SDS_TYPE_8 1 -#define SDS_TYPE_16 2 -#define SDS_TYPE_32 3 -#define SDS_TYPE_64 4 -#define SDS_TYPE_MASK 7 -#define SDS_TYPE_BITS 3 -#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))); -#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T)))) -#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS) - static inline size_t sdslen(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - return SDS_TYPE_5_LEN(flags); - case SDS_TYPE_8: - return SDS_HDR(8,s)->len; - case SDS_TYPE_16: - return SDS_HDR(16,s)->len; - case SDS_TYPE_32: - return SDS_HDR(32,s)->len; - case SDS_TYPE_64: - return SDS_HDR(64,s)->len; - } - return 0; + struct sdshdr *sh = (struct sdshdr *)(s-sizeof *sh); + return sh->len; } static inline size_t sdsavail(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: { - return 0; - } - case SDS_TYPE_8: { - SDS_HDR_VAR(8,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_16: { - SDS_HDR_VAR(16,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_32: { - SDS_HDR_VAR(32,s); - return sh->alloc - sh->len; - } - case SDS_TYPE_64: { - SDS_HDR_VAR(64,s); - return sh->alloc - sh->len; - } - } - return 0; -} - -static inline void sdssetlen(sds s, size_t newlen) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - { - unsigned char *fp = ((unsigned char*)s)-1; - *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS); - } - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->len = newlen; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->len = newlen; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->len = newlen; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->len = newlen; - break; - } -} - -static inline void sdsinclen(sds s, size_t inc) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - { - unsigned char *fp = ((unsigned char*)s)-1; - unsigned char newlen = SDS_TYPE_5_LEN(flags)+inc; - *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS); - } - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->len += inc; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->len += inc; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->len += inc; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->len += inc; - break; - } -} - -/* sdsalloc() = sdsavail() + sdslen() */ -static inline size_t sdsalloc(const sds s) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - return SDS_TYPE_5_LEN(flags); - case SDS_TYPE_8: - return SDS_HDR(8,s)->alloc; - case SDS_TYPE_16: - return SDS_HDR(16,s)->alloc; - case SDS_TYPE_32: - return SDS_HDR(32,s)->alloc; - case SDS_TYPE_64: - return SDS_HDR(64,s)->alloc; - } - return 0; -} - -static inline void sdssetalloc(sds s, size_t newlen) { - unsigned char flags = s[-1]; - switch(flags&SDS_TYPE_MASK) { - case SDS_TYPE_5: - /* Nothing to do, this type has no total allocation info. */ - break; - case SDS_TYPE_8: - SDS_HDR(8,s)->alloc = newlen; - break; - case SDS_TYPE_16: - SDS_HDR(16,s)->alloc = newlen; - break; - case SDS_TYPE_32: - SDS_HDR(32,s)->alloc = newlen; - break; - case SDS_TYPE_64: - SDS_HDR(64,s)->alloc = newlen; - break; - } + struct sdshdr *sh = (struct sdshdr *)(s-sizeof *sh); + return sh->free; } sds sdsnewlen(const void *init, size_t initlen); sds sdsnew(const char *init); sds sdsempty(void); +size_t sdslen(const sds s); sds sdsdup(const sds s); void sdsfree(sds s); +size_t sdsavail(const sds s); sds sdsgrowzero(sds s, size_t len); sds sdscatlen(sds s, const void *t, size_t len); sds sdscat(sds s, const char *t); @@ -235,7 +80,7 @@ sds sdscatprintf(sds s, const char *fmt, ...); #endif sds sdscatfmt(sds s, char const *fmt, ...); -sds sdstrim(sds s, const char *cset); +void sdstrim(sds s, const char *cset); void sdsrange(sds s, int start, int end); void sdsupdatelen(sds s); void sdsclear(sds s); @@ -248,7 +93,7 @@ sds sdsfromlonglong(long long value); sds sdscatrepr(sds s, const char *p, size_t len); sds *sdssplitargs(const char *line, int *argc); sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen); -sds sdsjoin(char **argv, int argc, char *sep); +sds sdsjoin(char **argv, int argc, char *sep, size_t seplen); sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen); /* Low level functions exposed to the user API */ @@ -256,18 +101,5 @@ sds sdsMakeRoomFor(sds s, size_t addlen); void sdsIncrLen(sds s, int incr); sds sdsRemoveFreeSpace(sds s); size_t sdsAllocSize(sds s); -void *sdsAllocPtr(sds s); - -/* Export the allocator used by SDS to the program using SDS. - * Sometimes the program SDS is linked to, may use a different set of - * allocators, but may want to allocate or free things that SDS will - * respectively free or allocate. */ -void *sds_malloc(size_t size); -void *sds_realloc(void *ptr, size_t size); -void sds_free(void *ptr); - -#ifdef REDIS_TEST -int sdsTest(int argc, char *argv[]); -#endif #endif diff --git a/third-party/hiredis/sdsalloc.h b/third-party/hiredis/sdsalloc.h deleted file mode 100644 index f43023c48..000000000 --- a/third-party/hiredis/sdsalloc.h +++ /dev/null @@ -1,42 +0,0 @@ -/* SDSLib 2.0 -- A C dynamic strings library - * - * Copyright (c) 2006-2015, Salvatore Sanfilippo - * Copyright (c) 2015, Oran Agra - * Copyright (c) 2015, Redis Labs, Inc - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* SDS allocator selection. - * - * This file is used in order to change the SDS allocator at compile time. - * Just define the following defines to what you want to use. Also add - * the include of your alternate allocator if needed (not needed in order - * to use the default libc allocator). */ - -#define s_malloc malloc -#define s_realloc realloc -#define s_free free diff --git a/third-party/hiredis/test.c b/third-party/hiredis/test.c index a23d60676..d5e82170d 100644 --- a/third-party/hiredis/test.c +++ b/third-party/hiredis/test.c @@ -30,7 +30,7 @@ struct config { struct { const char *path; - } unix_sock; + } unix; }; /* The following lines make up our testing "framework" :) */ @@ -97,10 +97,10 @@ static redisContext *connect(struct config config) { if (config.type == CONN_TCP) { c = redisConnect(config.tcp.host, config.tcp.port); } else if (config.type == CONN_UNIX) { - c = redisConnectUnix(config.unix_sock.path); + c = redisConnectUnix(config.unix.path); } else if (config.type == CONN_FD) { /* Create a dummy connection just to get an fd to inherit */ - redisContext *dummy_ctx = redisConnectUnix(config.unix_sock.path); + redisContext *dummy_ctx = redisConnectUnix(config.unix.path); if (dummy_ctx) { int fd = disconnect(dummy_ctx, 1); printf("Connecting to inherited fd %d\n", fd); @@ -224,22 +224,6 @@ static void test_format_commands(void) { test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 && len == 4+4+(3+2)+4+(7+2)+4+(3+2)); free(cmd); - - sds sds_cmd; - - sds_cmd = sdsempty(); - test("Format command into sds by passing argc/argv without lengths: "); - len = redisFormatSdsCommandArgv(&sds_cmd,argc,argv,NULL); - test_cond(strncmp(sds_cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && - len == 4+4+(3+2)+4+(3+2)+4+(3+2)); - sdsfree(sds_cmd); - - sds_cmd = sdsempty(); - test("Format command into sds by passing argc/argv with lengths: "); - len = redisFormatSdsCommandArgv(&sds_cmd,argc,argv,lens); - test_cond(strncmp(sds_cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 && - len == 4+4+(3+2)+4+(7+2)+4+(3+2)); - sdsfree(sds_cmd); } static void test_append_formatted_commands(struct config config) { @@ -344,12 +328,12 @@ static void test_reply_reader(void) { } static void test_free_null(void) { - void *redisCtx = NULL; + void *redisContext = NULL; void *reply = NULL; test("Don't fail when redisFree is passed a NULL value: "); - redisFree(redisCtx); - test_cond(redisCtx == NULL); + redisFree(redisContext); + test_cond(redisContext == NULL); test("Don't fail when freeReplyObject is passed a NULL value: "); freeReplyObject(reply); @@ -377,7 +361,7 @@ static void test_blocking_connection_errors(void) { strcmp(c->errstr,"Connection refused") == 0); redisFree(c); - test("Returns error when the unix_sock socket path doesn't accept connections: "); + test("Returns error when the unix socket path doesn't accept connections: "); c = redisConnectUnix((char*)"/tmp/idontexist.sock"); test_cond(c->err == REDIS_ERR_IO); /* Don't care about the message... */ redisFree(c); @@ -498,7 +482,7 @@ static void test_blocking_connection_timeouts(struct config config) { test("Reconnect properly uses owned parameters: "); config.tcp.host = "foo"; - config.unix_sock.path = "foo"; + config.unix.path = "foo"; redisReconnect(c); reply = redisCommand(c, "PING"); test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "PONG") == 0); @@ -568,7 +552,7 @@ static void test_invalid_timeout_errors(struct config config) { c = redisConnectWithTimeout(config.tcp.host, config.tcp.port, config.tcp.timeout); - test_cond(c->err == REDIS_ERR_IO && strcmp(c->errstr, "Invalid timeout specified") == 0); + test_cond(c->err == REDIS_ERR_IO); redisFree(c); test("Set error when an invalid timeout sec value is given to redisConnectWithTimeout: "); @@ -578,7 +562,7 @@ static void test_invalid_timeout_errors(struct config config) { c = redisConnectWithTimeout(config.tcp.host, config.tcp.port, config.tcp.timeout); - test_cond(c->err == REDIS_ERR_IO && strcmp(c->errstr, "Invalid timeout specified") == 0); + test_cond(c->err == REDIS_ERR_IO); redisFree(c); } @@ -752,7 +736,7 @@ int main(int argc, char **argv) { .host = "127.0.0.1", .port = 6379 }, - .unix_sock = { + .unix = { .path = "/tmp/redis.sock" } }; @@ -773,7 +757,7 @@ int main(int argc, char **argv) { cfg.tcp.port = atoi(argv[0]); } else if (argc >= 2 && !strcmp(argv[0],"-s")) { argv++; argc--; - cfg.unix_sock.path = argv[0]; + cfg.unix.path = argv[0]; } else if (argc >= 1 && !strcmp(argv[0],"--skip-throughput")) { throughput = 0; } else if (argc >= 1 && !strcmp(argv[0],"--skip-inherit-fd")) { @@ -799,7 +783,7 @@ int main(int argc, char **argv) { test_append_formatted_commands(cfg); if (throughput) test_throughput(cfg); - printf("\nTesting against Unix socket connection (%s):\n", cfg.unix_sock.path); + printf("\nTesting against Unix socket connection (%s):\n", cfg.unix.path); cfg.type = CONN_UNIX; test_blocking_connection(cfg); test_blocking_connection_timeouts(cfg); @@ -807,7 +791,7 @@ int main(int argc, char **argv) { if (throughput) test_throughput(cfg); if (test_inherit_fd) { - printf("\nTesting against inherited fd (%s):\n", cfg.unix_sock.path); + printf("\nTesting against inherited fd (%s):\n", cfg.unix.path); cfg.type = CONN_FD; test_blocking_connection(cfg); } -- 2.40.0