hiredis 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +1 -0
- data/ext/hiredis_ext/connection.c +1 -1
- data/ext/hiredis_ext/extconf.rb +9 -13
- data/ext/hiredis_ext/reader.c +12 -15
- data/lib/hiredis/version.rb +1 -1
- data/vendor/hiredis/COPYING +25 -6
- data/vendor/hiredis/Makefile +60 -48
- data/vendor/hiredis/async.c +4 -11
- data/vendor/hiredis/async.h +2 -3
- data/vendor/hiredis/fmacros.h +4 -5
- data/vendor/hiredis/hiredis.c +417 -255
- data/vendor/hiredis/hiredis.h +52 -32
- data/vendor/hiredis/net.c +29 -25
- data/vendor/hiredis/net.h +2 -2
- data/vendor/hiredis/sds.c +24 -23
- data/vendor/hiredis/sds.h +10 -0
- data/vendor/hiredis/test.c +83 -52
- metadata +14 -27
- data/vendor/hiredis/util.h +0 -40
    
        data/Rakefile
    CHANGED
    
    
    
        data/ext/hiredis_ext/extconf.rb
    CHANGED
    
    | @@ -2,20 +2,16 @@ require 'mkmf' | |
| 2 2 |  | 
| 3 3 | 
             
            RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
         | 
| 4 4 |  | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 5 | 
            +
            hiredis_dir = File.expand_path(File.join(File.dirname(__FILE__), %w{.. .. vendor hiredis}))
         | 
| 6 | 
            +
            unless File.directory?(hiredis_dir)
         | 
| 7 | 
            +
              STDERR.puts "vendor/hiredis missing, please checkout its submodule..."
         | 
| 8 | 
            +
              exit 1
         | 
| 7 9 | 
             
            end
         | 
| 8 10 |  | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
            end
         | 
| 12 | 
            -
             | 
| 13 | 
            -
            bundled_hiredis_dir = File.join(File.dirname(__FILE__), %w{.. .. vendor hiredis})
         | 
| 14 | 
            -
            dir_config('hiredis', bundled_hiredis_dir, bundled_hiredis_dir)
         | 
| 15 | 
            -
             | 
| 16 | 
            -
            # Compile hiredis when the bundled version can be found
         | 
| 17 | 
            -
            system("cd #{bundled_hiredis_dir} && make static") if File.directory?(bundled_hiredis_dir)
         | 
| 11 | 
            +
            # Make sure hiredis is built...
         | 
| 12 | 
            +
            system("cd #{hiredis_dir} && make static")
         | 
| 18 13 |  | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 14 | 
            +
            # Statically link to hiredis (mkmf can't do this for us)
         | 
| 15 | 
            +
            $CFLAGS << " -I#{hiredis_dir}"
         | 
| 16 | 
            +
            $LDFLAGS << " #{hiredis_dir}/libhiredis.a"
         | 
| 21 17 | 
             
            create_makefile('hiredis/ext/hiredis_ext')
         | 
    
        data/ext/hiredis_ext/reader.c
    CHANGED
    
    | @@ -61,38 +61,35 @@ redisReplyObjectFunctions redisExtReplyObjectFunctions = { | |
| 61 61 | 
             
                freeObject
         | 
| 62 62 | 
             
            };
         | 
| 63 63 |  | 
| 64 | 
            -
            static void reader_mark( | 
| 65 | 
            -
                VALUE root;
         | 
| 66 | 
            -
                root = (VALUE)redisReplyReaderGetObject(reader);
         | 
| 64 | 
            +
            static void reader_mark(redisReader *reader) {
         | 
| 65 | 
            +
                VALUE root = (VALUE)reader->reply;
         | 
| 67 66 | 
             
                if (root != 0 && TYPE(root) == T_ARRAY) rb_gc_mark(root);
         | 
| 68 67 | 
             
            }
         | 
| 69 68 |  | 
| 70 69 | 
             
            static VALUE reader_allocate(VALUE klass) {
         | 
| 71 | 
            -
                 | 
| 72 | 
            -
                 | 
| 73 | 
            -
                return Data_Wrap_Struct(klass, reader_mark,  | 
| 70 | 
            +
                redisReader *reader = redisReaderCreate();
         | 
| 71 | 
            +
                reader->fn = &redisExtReplyObjectFunctions;
         | 
| 72 | 
            +
                return Data_Wrap_Struct(klass, reader_mark, redisReaderFree, reader);
         | 
| 74 73 | 
             
            }
         | 
| 75 74 |  | 
| 76 75 | 
             
            static VALUE reader_feed(VALUE klass, VALUE str) {
         | 
| 77 | 
            -
                 | 
| 76 | 
            +
                redisReader *reader;
         | 
| 78 77 |  | 
| 79 78 | 
             
                if (TYPE(str) != T_STRING)
         | 
| 80 79 | 
             
                    rb_raise(rb_eTypeError, "not a string");
         | 
| 81 80 |  | 
| 82 | 
            -
                Data_Get_Struct(klass,  | 
| 83 | 
            -
                 | 
| 81 | 
            +
                Data_Get_Struct(klass, redisReader, reader);
         | 
| 82 | 
            +
                redisReaderFeed(reader,RSTRING_PTR(str),(size_t)RSTRING_LEN(str));
         | 
| 84 83 | 
             
                return INT2NUM(0);
         | 
| 85 84 | 
             
            }
         | 
| 86 85 |  | 
| 87 86 | 
             
            static VALUE reader_gets(VALUE klass) {
         | 
| 88 | 
            -
                 | 
| 87 | 
            +
                redisReader *reader;
         | 
| 89 88 | 
             
                VALUE reply;
         | 
| 90 89 |  | 
| 91 | 
            -
                Data_Get_Struct(klass,  | 
| 92 | 
            -
                if ( | 
| 93 | 
            -
                     | 
| 94 | 
            -
                    rb_raise(rb_eRuntimeError,"%s",errstr);
         | 
| 95 | 
            -
                }
         | 
| 90 | 
            +
                Data_Get_Struct(klass, redisReader, reader);
         | 
| 91 | 
            +
                if (redisReaderGetReply(reader,(void**)&reply) != REDIS_OK)
         | 
| 92 | 
            +
                    rb_raise(rb_eRuntimeError,"%s",reader->errstr);
         | 
| 96 93 |  | 
| 97 94 | 
             
                return reply;
         | 
| 98 95 | 
             
            }
         | 
    
        data/lib/hiredis/version.rb
    CHANGED
    
    
    
        data/vendor/hiredis/COPYING
    CHANGED
    
    | @@ -1,10 +1,29 @@ | |
| 1 | 
            -
            Copyright (c)  | 
| 1 | 
            +
            Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
         | 
| 2 | 
            +
            Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
         | 
| 3 | 
            +
             | 
| 2 4 | 
             
            All rights reserved.
         | 
| 3 5 |  | 
| 4 | 
            -
            Redistribution and use in source and binary forms, with or without | 
| 6 | 
            +
            Redistribution and use in source and binary forms, with or without
         | 
| 7 | 
            +
            modification, are permitted provided that the following conditions are met:
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            * Redistributions of source code must retain the above copyright notice,
         | 
| 10 | 
            +
              this list of conditions and the following disclaimer.
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            * Redistributions in binary form must reproduce the above copyright notice,
         | 
| 13 | 
            +
              this list of conditions and the following disclaimer in the documentation
         | 
| 14 | 
            +
              and/or other materials provided with the distribution.
         | 
| 5 15 |  | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 16 | 
            +
            * Neither the name of Redis nor the names of its contributors may be used
         | 
| 17 | 
            +
              to endorse or promote products derived from this software without specific
         | 
| 18 | 
            +
              prior written permission.
         | 
| 9 19 |  | 
| 10 | 
            -
            THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | 
| 20 | 
            +
            THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
         | 
| 21 | 
            +
            ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
         | 
| 22 | 
            +
            WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
         | 
| 23 | 
            +
            DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
         | 
| 24 | 
            +
            ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
         | 
| 25 | 
            +
            (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
         | 
| 26 | 
            +
            LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
         | 
| 27 | 
            +
            ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
         | 
| 28 | 
            +
            (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
         | 
| 29 | 
            +
            SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
         | 
    
        data/vendor/hiredis/Makefile
    CHANGED
    
    | @@ -2,99 +2,111 @@ | |
| 2 2 | 
             
            # Copyright (C) 2010 Salvatore Sanfilippo <antirez at gmail dot com>
         | 
| 3 3 | 
             
            # This file is released under the BSD license, see the COPYING file
         | 
| 4 4 |  | 
| 5 | 
            -
            OBJ | 
| 6 | 
            -
            BINS | 
| 5 | 
            +
            OBJ=net.o hiredis.o sds.o async.o
         | 
| 6 | 
            +
            BINS=hiredis-example hiredis-test
         | 
| 7 | 
            +
            LIBNAME=libhiredis
         | 
| 7 8 |  | 
| 8 9 | 
             
            uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
         | 
| 9 10 | 
             
            OPTIMIZATION?=-O3
         | 
| 10 11 | 
             
            ifeq ($(uname_S),SunOS)
         | 
| 11 | 
            -
              CFLAGS | 
| 12 | 
            +
              CFLAGS?=$(OPTIMIZATION) -fPIC -Wall -W -D__EXTENSIONS__ -D_XPG6 $(ARCH) $(PROF)
         | 
| 12 13 | 
             
              CCLINK?=-ldl -lnsl -lsocket -lm -lpthread
         | 
| 13 | 
            -
              LDFLAGS?=-L. | 
| 14 | 
            -
               | 
| 15 | 
            -
               | 
| 16 | 
            -
               | 
| 17 | 
            -
               | 
| 18 | 
            -
             | 
| 19 | 
            -
               | 
| 14 | 
            +
              LDFLAGS?=-L.
         | 
| 15 | 
            +
              DYLIBSUFFIX=so
         | 
| 16 | 
            +
              STLIBSUFFIX=a
         | 
| 17 | 
            +
              DYLIBNAME?=$(LIBNAME).$(DYLIBSUFFIX)
         | 
| 18 | 
            +
              DYLIB_MAKE_CMD?=$(CC) -G -o $(DYLIBNAME)
         | 
| 19 | 
            +
              STLIBNAME?=$(LIBNAME).$(STLIBSUFFIX)
         | 
| 20 | 
            +
              STLIB_MAKE_CMD?=ar rcs $(STLIBNAME)
         | 
| 21 | 
            +
            else
         | 
| 22 | 
            +
            ifeq ($(uname_S),Darwin)
         | 
| 23 | 
            +
              CFLAGS?=$(OPTIMIZATION) -fPIC -Wall -W -Wstrict-prototypes -Wwrite-strings $(ARCH) $(PROF)
         | 
| 20 24 | 
             
              CCLINK?=-lm -pthread
         | 
| 21 | 
            -
              LDFLAGS?=-L. | 
| 25 | 
            +
              LDFLAGS?=-L.
         | 
| 22 26 | 
             
              OBJARCH?=-arch i386 -arch x86_64
         | 
| 23 | 
            -
               | 
| 24 | 
            -
               | 
| 25 | 
            -
               | 
| 26 | 
            -
               | 
| 27 | 
            +
              DYLIBSUFFIX=dylib
         | 
| 28 | 
            +
              STLIBSUFFIX=a
         | 
| 29 | 
            +
              DYLIBNAME?=$(LIBNAME).$(DYLIBSUFFIX)
         | 
| 30 | 
            +
              DYLIB_MAKE_CMD?=libtool -dynamic -o $(DYLIBNAME) -lm $(DEBUG) -
         | 
| 31 | 
            +
              STLIBNAME?=$(LIBNAME).$(STLIBSUFFIX)
         | 
| 32 | 
            +
              STLIB_MAKE_CMD?=libtool -static -o $(STLIBNAME) -
         | 
| 27 33 | 
             
            else
         | 
| 28 | 
            -
              CFLAGS | 
| 34 | 
            +
              CFLAGS?=$(OPTIMIZATION) -fPIC -Wall -W -Wstrict-prototypes -Wwrite-strings $(ARCH) $(PROF)
         | 
| 29 35 | 
             
              CCLINK?=-lm -pthread
         | 
| 30 | 
            -
              LDFLAGS?=-L. | 
| 31 | 
            -
               | 
| 32 | 
            -
               | 
| 33 | 
            -
               | 
| 34 | 
            -
               | 
| 36 | 
            +
              LDFLAGS?=-L.
         | 
| 37 | 
            +
              DYLIBSUFFIX=so
         | 
| 38 | 
            +
              STLIBSUFFIX=a
         | 
| 39 | 
            +
              DYLIBNAME?=$(LIBNAME).$(DYLIBSUFFIX)
         | 
| 40 | 
            +
              DYLIB_MAKE_CMD?=gcc -shared -Wl,-soname,$(DYLIBNAME) -o $(DYLIBNAME)
         | 
| 41 | 
            +
              STLIBNAME?=$(LIBNAME).$(STLIBSUFFIX)
         | 
| 42 | 
            +
              STLIB_MAKE_CMD?=ar rcs $(STLIBNAME)
         | 
| 43 | 
            +
            endif
         | 
| 35 44 | 
             
            endif
         | 
| 45 | 
            +
             | 
| 36 46 | 
             
            CCOPT= $(CFLAGS) $(CCLINK)
         | 
| 37 47 | 
             
            DEBUG?= -g -ggdb
         | 
| 38 48 |  | 
| 39 | 
            -
            PREFIX | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 49 | 
            +
            PREFIX?=/usr/local
         | 
| 50 | 
            +
            INCLUDE_PATH?=include/hiredis
         | 
| 51 | 
            +
            LIBRARY_PATH?=lib
         | 
| 52 | 
            +
            INSTALL_INCLUDE_PATH= $(PREFIX)/$(INCLUDE_PATH)
         | 
| 53 | 
            +
            INSTALL_LIBRARY_PATH= $(PREFIX)/$(LIBRARY_PATH)
         | 
| 42 54 | 
             
            INSTALL= cp -a
         | 
| 43 55 |  | 
| 44 | 
            -
            all: $ | 
| 56 | 
            +
            all: $(DYLIBNAME) $(BINS)
         | 
| 45 57 |  | 
| 46 58 | 
             
            # Deps (use make dep to generate this)
         | 
| 47 | 
            -
            net.o: net.c fmacros.h net.h
         | 
| 48 | 
            -
            async.o: async.c async.h hiredis.h sds.h  | 
| 59 | 
            +
            net.o: net.c fmacros.h net.h hiredis.h
         | 
| 60 | 
            +
            async.o: async.c async.h hiredis.h sds.h dict.c dict.h
         | 
| 49 61 | 
             
            example.o: example.c hiredis.h
         | 
| 50 | 
            -
            hiredis.o: hiredis.c hiredis.h net.h sds.h | 
| 62 | 
            +
            hiredis.o: hiredis.c fmacros.h hiredis.h net.h sds.h
         | 
| 51 63 | 
             
            sds.o: sds.c sds.h
         | 
| 52 64 | 
             
            test.o: test.c hiredis.h
         | 
| 53 65 |  | 
| 54 | 
            -
            $ | 
| 55 | 
            -
            	$ | 
| 66 | 
            +
            $(DYLIBNAME): $(OBJ)
         | 
| 67 | 
            +
            	$(DYLIB_MAKE_CMD) $(OBJ)
         | 
| 56 68 |  | 
| 57 | 
            -
            $ | 
| 58 | 
            -
            	$ | 
| 69 | 
            +
            $(STLIBNAME): $(OBJ)
         | 
| 70 | 
            +
            	$(STLIB_MAKE_CMD) $(OBJ)
         | 
| 59 71 |  | 
| 60 | 
            -
            dynamic: $ | 
| 61 | 
            -
            static: $ | 
| 72 | 
            +
            dynamic: $(DYLIBNAME)
         | 
| 73 | 
            +
            static: $(STLIBNAME)
         | 
| 62 74 |  | 
| 63 75 | 
             
            # Binaries:
         | 
| 64 | 
            -
            hiredis-example-libevent: example-libevent.c adapters/libevent.h $ | 
| 65 | 
            -
            	$(CC) -o $@ $(CCOPT) $(DEBUG) $(LDFLAGS)  | 
| 76 | 
            +
            hiredis-example-libevent: example-libevent.c adapters/libevent.h $(STLIBNAME)
         | 
| 77 | 
            +
            	$(CC) -o $@ $(CCOPT) $(DEBUG) $(LDFLAGS) $(STLIBNAME) example-libevent.c -levent
         | 
| 66 78 |  | 
| 67 | 
            -
            hiredis-example-libev: example-libev.c adapters/libev.h $ | 
| 68 | 
            -
            	$(CC) -o $@ $(CCOPT) $(DEBUG) $(LDFLAGS)  | 
| 79 | 
            +
            hiredis-example-libev: example-libev.c adapters/libev.h $(STLIBNAME)
         | 
| 80 | 
            +
            	$(CC) -o $@ $(CCOPT) $(DEBUG) $(LDFLAGS) $(STLIBNAME) example-libev.c -lev
         | 
| 69 81 |  | 
| 70 82 | 
             
            ifndef AE_DIR
         | 
| 71 83 | 
             
            hiredis-example-ae:
         | 
| 72 84 | 
             
            	@echo "Please specify AE_DIR (e.g. <redis repository>/src)"
         | 
| 73 85 | 
             
            	@false
         | 
| 74 86 | 
             
            else
         | 
| 75 | 
            -
            hiredis-example-ae: example-ae.c adapters/ae.h $ | 
| 76 | 
            -
            	$(CC) -o $@ $(CCOPT) $(DEBUG) -I$(AE_DIR) $(LDFLAGS)  | 
| 87 | 
            +
            hiredis-example-ae: example-ae.c adapters/ae.h $(STLIBNAME)
         | 
| 88 | 
            +
            	$(CC) -o $@ $(CCOPT) $(DEBUG) -I$(AE_DIR) $(LDFLAGS) $(STLIBNAME) example-ae.c $(AE_DIR)/ae.o $(AE_DIR)/zmalloc.o
         | 
| 77 89 | 
             
            endif
         | 
| 78 90 |  | 
| 79 | 
            -
            hiredis-%: %.o $ | 
| 80 | 
            -
            	$(CC) -o $@ $(CCOPT) $(DEBUG) $(LDFLAGS)  | 
| 91 | 
            +
            hiredis-%: %.o $(STLIBNAME)
         | 
| 92 | 
            +
            	$(CC) -o $@ $(CCOPT) $(DEBUG) $(LDFLAGS) $(STLIBNAME) $<
         | 
| 81 93 |  | 
| 82 94 | 
             
            test: hiredis-test
         | 
| 83 95 | 
             
            	./hiredis-test
         | 
| 84 96 |  | 
| 85 97 | 
             
            .c.o:
         | 
| 86 | 
            -
            	$(CC) -c $(CFLAGS) $(OBJARCH) $(DEBUG) $(COMPILE_TIME) $<
         | 
| 98 | 
            +
            	$(CC) -std=c99 -pedantic -c $(CFLAGS) $(OBJARCH) $(DEBUG) $(COMPILE_TIME) $<
         | 
| 87 99 |  | 
| 88 100 | 
             
            clean:
         | 
| 89 | 
            -
            	rm -rf $ | 
| 101 | 
            +
            	rm -rf $(DYLIBNAME) $(STLIBNAME) $(BINS) hiredis-example* *.o *.gcda *.gcno *.gcov
         | 
| 90 102 |  | 
| 91 103 | 
             
            dep:
         | 
| 92 104 | 
             
            	$(CC) -MM *.c
         | 
| 93 105 |  | 
| 94 | 
            -
            install: $ | 
| 95 | 
            -
            	mkdir -p $( | 
| 96 | 
            -
            	$(INSTALL) hiredis.h async.h adapters $( | 
| 97 | 
            -
            	$(INSTALL) $ | 
| 106 | 
            +
            install: $(DYLIBNAME) $(STLIBNAME)
         | 
| 107 | 
            +
            	mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH)
         | 
| 108 | 
            +
            	$(INSTALL) hiredis.h async.h adapters $(INSTALL_INCLUDE_PATH)
         | 
| 109 | 
            +
            	$(INSTALL) $(DYLIBNAME) $(STLIBNAME) $(INSTALL_LIBRARY_PATH)
         | 
| 98 110 |  | 
| 99 111 | 
             
            32bit:
         | 
| 100 112 | 
             
            	@echo ""
         | 
    
        data/vendor/hiredis/async.c
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            /*
         | 
| 2 | 
            -
             * Copyright (c) 2009- | 
| 3 | 
            -
             * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
         | 
| 2 | 
            +
             * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
         | 
| 3 | 
            +
             * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
         | 
| 4 4 | 
             
             *
         | 
| 5 5 | 
             
             * All rights reserved.
         | 
| 6 6 | 
             
             *
         | 
| @@ -36,7 +36,6 @@ | |
| 36 36 | 
             
            #include "async.h"
         | 
| 37 37 | 
             
            #include "dict.c"
         | 
| 38 38 | 
             
            #include "sds.h"
         | 
| 39 | 
            -
            #include "util.h"
         | 
| 40 39 |  | 
| 41 40 | 
             
            /* Forward declaration of function in hiredis.c */
         | 
| 42 41 | 
             
            void __redisAppendCommand(redisContext *c, char *cmd, size_t len);
         | 
| @@ -136,11 +135,6 @@ redisAsyncContext *redisAsyncConnectUnix(const char *path) { | |
| 136 135 | 
             
                return ac;
         | 
| 137 136 | 
             
            }
         | 
| 138 137 |  | 
| 139 | 
            -
            int redisAsyncSetReplyObjectFunctions(redisAsyncContext *ac, redisReplyObjectFunctions *fn) {
         | 
| 140 | 
            -
                redisContext *c = &(ac->c);
         | 
| 141 | 
            -
                return redisSetReplyObjectFunctions(c,fn);
         | 
| 142 | 
            -
            }
         | 
| 143 | 
            -
             | 
| 144 138 | 
             
            int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn) {
         | 
| 145 139 | 
             
                if (ac->onConnect == NULL) {
         | 
| 146 140 | 
             
                    ac->onConnect = fn;
         | 
| @@ -168,7 +162,6 @@ static int __redisPushCallback(redisCallbackList *list, redisCallback *source) { | |
| 168 162 |  | 
| 169 163 | 
             
                /* Copy callback from stack to heap */
         | 
| 170 164 | 
             
                cb = malloc(sizeof(*cb));
         | 
| 171 | 
            -
                if (!cb) redisOOM();
         | 
| 172 165 | 
             
                if (source != NULL) {
         | 
| 173 166 | 
             
                    memcpy(cb,source,sizeof(*cb));
         | 
| 174 167 | 
             
                    cb->next = NULL;
         | 
| @@ -375,7 +368,7 @@ void redisProcessCallbacks(redisAsyncContext *ac) { | |
| 375 368 |  | 
| 376 369 | 
             
                    if (cb.fn != NULL) {
         | 
| 377 370 | 
             
                        __redisRunCallback(ac,&cb,reply);
         | 
| 378 | 
            -
                        c->fn->freeObject(reply);
         | 
| 371 | 
            +
                        c->reader->fn->freeObject(reply);
         | 
| 379 372 |  | 
| 380 373 | 
             
                        /* Proceed with free'ing when redisAsyncFree() was called. */
         | 
| 381 374 | 
             
                        if (c->flags & REDIS_FREEING) {
         | 
| @@ -387,7 +380,7 @@ void redisProcessCallbacks(redisAsyncContext *ac) { | |
| 387 380 | 
             
                         * or there were no callbacks to begin with. Either way, don't
         | 
| 388 381 | 
             
                         * abort with an error, but simply ignore it because the client
         | 
| 389 382 | 
             
                         * doesn't know what the server will spit out over the wire. */
         | 
| 390 | 
            -
                        c->fn->freeObject(reply);
         | 
| 383 | 
            +
                        c->reader->fn->freeObject(reply);
         | 
| 391 384 | 
             
                    }
         | 
| 392 385 | 
             
                }
         | 
| 393 386 |  | 
    
        data/vendor/hiredis/async.h
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            /*
         | 
| 2 | 
            -
             * Copyright (c) 2009- | 
| 3 | 
            -
             * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
         | 
| 2 | 
            +
             * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
         | 
| 3 | 
            +
             * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
         | 
| 4 4 | 
             
             *
         | 
| 5 5 | 
             
             * All rights reserved.
         | 
| 6 6 | 
             
             *
         | 
| @@ -103,7 +103,6 @@ typedef struct redisAsyncContext { | |
| 103 103 | 
             
            /* Functions that proxy to hiredis */
         | 
| 104 104 | 
             
            redisAsyncContext *redisAsyncConnect(const char *ip, int port);
         | 
| 105 105 | 
             
            redisAsyncContext *redisAsyncConnectUnix(const char *path);
         | 
| 106 | 
            -
            int redisAsyncSetReplyObjectFunctions(redisAsyncContext *ac, redisReplyObjectFunctions *fn);
         | 
| 107 106 | 
             
            int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
         | 
| 108 107 | 
             
            int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
         | 
| 109 108 | 
             
            void redisAsyncDisconnect(redisAsyncContext *ac);
         | 
    
        data/vendor/hiredis/fmacros.h
    CHANGED
    
    | @@ -1,7 +1,9 @@ | |
| 1 | 
            -
            #ifndef  | 
| 2 | 
            -
            #define  | 
| 1 | 
            +
            #ifndef __HIREDIS_FMACRO_H
         | 
| 2 | 
            +
            #define __HIREDIS_FMACRO_H
         | 
| 3 3 |  | 
| 4 | 
            +
            #ifndef _BSD_SOURCE
         | 
| 4 5 | 
             
            #define _BSD_SOURCE
         | 
| 6 | 
            +
            #endif
         | 
| 5 7 |  | 
| 6 8 | 
             
            #ifdef __linux__
         | 
| 7 9 | 
             
            #define _XOPEN_SOURCE 700
         | 
| @@ -9,7 +11,4 @@ | |
| 9 11 | 
             
            #define _XOPEN_SOURCE
         | 
| 10 12 | 
             
            #endif
         | 
| 11 13 |  | 
| 12 | 
            -
            #define _LARGEFILE_SOURCE
         | 
| 13 | 
            -
            #define _FILE_OFFSET_BITS 64
         | 
| 14 | 
            -
             | 
| 15 14 | 
             
            #endif
         | 
    
        data/vendor/hiredis/hiredis.c
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            /*
         | 
| 2 | 
            -
             * Copyright (c) 2009- | 
| 3 | 
            -
             * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
         | 
| 2 | 
            +
             * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
         | 
| 3 | 
            +
             * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
         | 
| 4 4 | 
             
             *
         | 
| 5 5 | 
             
             * All rights reserved.
         | 
| 6 6 | 
             
             *
         | 
| @@ -29,6 +29,7 @@ | |
| 29 29 | 
             
             * POSSIBILITY OF SUCH DAMAGE.
         | 
| 30 30 | 
             
             */
         | 
| 31 31 |  | 
| 32 | 
            +
            #include "fmacros.h"
         | 
| 32 33 | 
             
            #include <string.h>
         | 
| 33 34 | 
             
            #include <stdlib.h>
         | 
| 34 35 | 
             
            #include <unistd.h>
         | 
| @@ -39,30 +40,15 @@ | |
| 39 40 | 
             
            #include "hiredis.h"
         | 
| 40 41 | 
             
            #include "net.h"
         | 
| 41 42 | 
             
            #include "sds.h"
         | 
| 42 | 
            -
            #include "util.h"
         | 
| 43 | 
            -
             | 
| 44 | 
            -
            typedef struct redisReader {
         | 
| 45 | 
            -
                struct redisReplyObjectFunctions *fn;
         | 
| 46 | 
            -
                sds error; /* holds optional error */
         | 
| 47 | 
            -
                void *reply; /* holds temporary reply */
         | 
| 48 | 
            -
             | 
| 49 | 
            -
                sds buf; /* read buffer */
         | 
| 50 | 
            -
                size_t pos; /* buffer cursor */
         | 
| 51 | 
            -
                size_t len; /* buffer length */
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                redisReadTask rstack[3]; /* stack of read tasks */
         | 
| 54 | 
            -
                int ridx; /* index of stack */
         | 
| 55 | 
            -
                void *privdata; /* user-settable arbitrary field */
         | 
| 56 | 
            -
            } redisReader;
         | 
| 57 43 |  | 
| 58 44 | 
             
            static redisReply *createReplyObject(int type);
         | 
| 59 45 | 
             
            static void *createStringObject(const redisReadTask *task, char *str, size_t len);
         | 
| 60 46 | 
             
            static void *createArrayObject(const redisReadTask *task, int elements);
         | 
| 61 47 | 
             
            static void *createIntegerObject(const redisReadTask *task, long long value);
         | 
| 62 48 | 
             
            static void *createNilObject(const redisReadTask *task);
         | 
| 63 | 
            -
            static void redisSetReplyReaderError(redisReader *r, sds err);
         | 
| 64 49 |  | 
| 65 | 
            -
            /* Default set of functions to build the reply.  | 
| 50 | 
            +
            /* Default set of functions to build the reply. Keep in mind that such a
         | 
| 51 | 
            +
             * function returning NULL is interpreted as OOM. */
         | 
| 66 52 | 
             
            static redisReplyObjectFunctions defaultFunctions = {
         | 
| 67 53 | 
             
                createStringObject,
         | 
| 68 54 | 
             
                createArrayObject,
         | 
| @@ -73,9 +59,11 @@ static redisReplyObjectFunctions defaultFunctions = { | |
| 73 59 |  | 
| 74 60 | 
             
            /* Create a reply object */
         | 
| 75 61 | 
             
            static redisReply *createReplyObject(int type) {
         | 
| 76 | 
            -
                redisReply *r =  | 
| 62 | 
            +
                redisReply *r = calloc(1,sizeof(*r));
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                if (r == NULL)
         | 
| 65 | 
            +
                    return NULL;
         | 
| 77 66 |  | 
| 78 | 
            -
                if (!r) redisOOM();
         | 
| 79 67 | 
             
                r->type = type;
         | 
| 80 68 | 
             
                return r;
         | 
| 81 69 | 
             
            }
         | 
| @@ -89,35 +77,49 @@ void freeReplyObject(void *reply) { | |
| 89 77 | 
             
                case REDIS_REPLY_INTEGER:
         | 
| 90 78 | 
             
                    break; /* Nothing to free */
         | 
| 91 79 | 
             
                case REDIS_REPLY_ARRAY:
         | 
| 92 | 
            -
                     | 
| 93 | 
            -
                         | 
| 94 | 
            -
             | 
| 80 | 
            +
                    if (r->elements > 0 && r->element != NULL) {
         | 
| 81 | 
            +
                        for (j = 0; j < r->elements; j++)
         | 
| 82 | 
            +
                            if (r->element[j] != NULL)
         | 
| 83 | 
            +
                                freeReplyObject(r->element[j]);
         | 
| 84 | 
            +
                        free(r->element);
         | 
| 85 | 
            +
                    }
         | 
| 95 86 | 
             
                    break;
         | 
| 96 87 | 
             
                case REDIS_REPLY_ERROR:
         | 
| 97 88 | 
             
                case REDIS_REPLY_STATUS:
         | 
| 98 89 | 
             
                case REDIS_REPLY_STRING:
         | 
| 99 | 
            -
                     | 
| 90 | 
            +
                    if (r->str != NULL)
         | 
| 91 | 
            +
                        free(r->str);
         | 
| 100 92 | 
             
                    break;
         | 
| 101 93 | 
             
                }
         | 
| 102 94 | 
             
                free(r);
         | 
| 103 95 | 
             
            }
         | 
| 104 96 |  | 
| 105 97 | 
             
            static void *createStringObject(const redisReadTask *task, char *str, size_t len) {
         | 
| 106 | 
            -
                redisReply *r  | 
| 107 | 
            -
                char * | 
| 108 | 
            -
             | 
| 109 | 
            -
                 | 
| 98 | 
            +
                redisReply *r, *parent;
         | 
| 99 | 
            +
                char *buf;
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                r = createReplyObject(task->type);
         | 
| 102 | 
            +
                if (r == NULL)
         | 
| 103 | 
            +
                    return NULL;
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                buf = malloc(len+1);
         | 
| 106 | 
            +
                if (buf == NULL) {
         | 
| 107 | 
            +
                    freeReplyObject(r);
         | 
| 108 | 
            +
                    return NULL;
         | 
| 109 | 
            +
                }
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                assert(task->type == REDIS_REPLY_ERROR  ||
         | 
| 110 112 | 
             
                       task->type == REDIS_REPLY_STATUS ||
         | 
| 111 113 | 
             
                       task->type == REDIS_REPLY_STRING);
         | 
| 112 114 |  | 
| 113 115 | 
             
                /* Copy string value */
         | 
| 114 | 
            -
                memcpy( | 
| 115 | 
            -
                 | 
| 116 | 
            -
                r->str =  | 
| 116 | 
            +
                memcpy(buf,str,len);
         | 
| 117 | 
            +
                buf[len] = '\0';
         | 
| 118 | 
            +
                r->str = buf;
         | 
| 117 119 | 
             
                r->len = len;
         | 
| 118 120 |  | 
| 119 121 | 
             
                if (task->parent) {
         | 
| 120 | 
            -
                     | 
| 122 | 
            +
                    parent = task->parent->obj;
         | 
| 121 123 | 
             
                    assert(parent->type == REDIS_REPLY_ARRAY);
         | 
| 122 124 | 
             
                    parent->element[task->idx] = r;
         | 
| 123 125 | 
             
                }
         | 
| @@ -125,12 +127,22 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len | |
| 125 127 | 
             
            }
         | 
| 126 128 |  | 
| 127 129 | 
             
            static void *createArrayObject(const redisReadTask *task, int elements) {
         | 
| 128 | 
            -
                redisReply *r  | 
| 130 | 
            +
                redisReply *r, *parent;
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                r = createReplyObject(REDIS_REPLY_ARRAY);
         | 
| 133 | 
            +
                if (r == NULL)
         | 
| 134 | 
            +
                    return NULL;
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                r->element = calloc(elements,sizeof(redisReply*));
         | 
| 137 | 
            +
                if (r->element == NULL) {
         | 
| 138 | 
            +
                    freeReplyObject(r);
         | 
| 139 | 
            +
                    return NULL;
         | 
| 140 | 
            +
                }
         | 
| 141 | 
            +
             | 
| 129 142 | 
             
                r->elements = elements;
         | 
| 130 | 
            -
             | 
| 131 | 
            -
                    redisOOM();
         | 
| 143 | 
            +
             | 
| 132 144 | 
             
                if (task->parent) {
         | 
| 133 | 
            -
                     | 
| 145 | 
            +
                    parent = task->parent->obj;
         | 
| 134 146 | 
             
                    assert(parent->type == REDIS_REPLY_ARRAY);
         | 
| 135 147 | 
             
                    parent->element[task->idx] = r;
         | 
| 136 148 | 
             
                }
         | 
| @@ -138,10 +150,16 @@ static void *createArrayObject(const redisReadTask *task, int elements) { | |
| 138 150 | 
             
            }
         | 
| 139 151 |  | 
| 140 152 | 
             
            static void *createIntegerObject(const redisReadTask *task, long long value) {
         | 
| 141 | 
            -
                redisReply *r  | 
| 153 | 
            +
                redisReply *r, *parent;
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                r = createReplyObject(REDIS_REPLY_INTEGER);
         | 
| 156 | 
            +
                if (r == NULL)
         | 
| 157 | 
            +
                    return NULL;
         | 
| 158 | 
            +
             | 
| 142 159 | 
             
                r->integer = value;
         | 
| 160 | 
            +
             | 
| 143 161 | 
             
                if (task->parent) {
         | 
| 144 | 
            -
                     | 
| 162 | 
            +
                    parent = task->parent->obj;
         | 
| 145 163 | 
             
                    assert(parent->type == REDIS_REPLY_ARRAY);
         | 
| 146 164 | 
             
                    parent->element[task->idx] = r;
         | 
| 147 165 | 
             
                }
         | 
| @@ -149,15 +167,83 @@ static void *createIntegerObject(const redisReadTask *task, long long value) { | |
| 149 167 | 
             
            }
         | 
| 150 168 |  | 
| 151 169 | 
             
            static void *createNilObject(const redisReadTask *task) {
         | 
| 152 | 
            -
                redisReply *r  | 
| 170 | 
            +
                redisReply *r, *parent;
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                r = createReplyObject(REDIS_REPLY_NIL);
         | 
| 173 | 
            +
                if (r == NULL)
         | 
| 174 | 
            +
                    return NULL;
         | 
| 175 | 
            +
             | 
| 153 176 | 
             
                if (task->parent) {
         | 
| 154 | 
            -
                     | 
| 177 | 
            +
                    parent = task->parent->obj;
         | 
| 155 178 | 
             
                    assert(parent->type == REDIS_REPLY_ARRAY);
         | 
| 156 179 | 
             
                    parent->element[task->idx] = r;
         | 
| 157 180 | 
             
                }
         | 
| 158 181 | 
             
                return r;
         | 
| 159 182 | 
             
            }
         | 
| 160 183 |  | 
| 184 | 
            +
            static void __redisReaderSetError(redisReader *r, int type, const char *str) {
         | 
| 185 | 
            +
                size_t len;
         | 
| 186 | 
            +
             | 
| 187 | 
            +
                if (r->reply != NULL && r->fn && r->fn->freeObject) {
         | 
| 188 | 
            +
                    r->fn->freeObject(r->reply);
         | 
| 189 | 
            +
                    r->reply = NULL;
         | 
| 190 | 
            +
                }
         | 
| 191 | 
            +
             | 
| 192 | 
            +
                /* Clear input buffer on errors. */
         | 
| 193 | 
            +
                if (r->buf != NULL) {
         | 
| 194 | 
            +
                    sdsfree(r->buf);
         | 
| 195 | 
            +
                    r->buf = NULL;
         | 
| 196 | 
            +
                    r->pos = r->len = 0;
         | 
| 197 | 
            +
                }
         | 
| 198 | 
            +
             | 
| 199 | 
            +
                /* Reset task stack. */
         | 
| 200 | 
            +
                r->ridx = -1;
         | 
| 201 | 
            +
             | 
| 202 | 
            +
                /* Set error. */
         | 
| 203 | 
            +
                r->err = type;
         | 
| 204 | 
            +
                len = strlen(str);
         | 
| 205 | 
            +
                len = len < (sizeof(r->errstr)-1) ? len : (sizeof(r->errstr)-1);
         | 
| 206 | 
            +
                memcpy(r->errstr,str,len);
         | 
| 207 | 
            +
                r->errstr[len] = '\0';
         | 
| 208 | 
            +
            }
         | 
| 209 | 
            +
             | 
| 210 | 
            +
            static size_t chrtos(char *buf, size_t size, char byte) {
         | 
| 211 | 
            +
                size_t len = 0;
         | 
| 212 | 
            +
             | 
| 213 | 
            +
                switch(byte) {
         | 
| 214 | 
            +
                case '\\':
         | 
| 215 | 
            +
                case '"':
         | 
| 216 | 
            +
                    len = snprintf(buf,size,"\"\\%c\"",byte);
         | 
| 217 | 
            +
                    break;
         | 
| 218 | 
            +
                case '\n': len = snprintf(buf,size,"\"\\n\""); break;
         | 
| 219 | 
            +
                case '\r': len = snprintf(buf,size,"\"\\r\""); break;
         | 
| 220 | 
            +
                case '\t': len = snprintf(buf,size,"\"\\t\""); break;
         | 
| 221 | 
            +
                case '\a': len = snprintf(buf,size,"\"\\a\""); break;
         | 
| 222 | 
            +
                case '\b': len = snprintf(buf,size,"\"\\b\""); break;
         | 
| 223 | 
            +
                default:
         | 
| 224 | 
            +
                    if (isprint(byte))
         | 
| 225 | 
            +
                        len = snprintf(buf,size,"\"%c\"",byte);
         | 
| 226 | 
            +
                    else
         | 
| 227 | 
            +
                        len = snprintf(buf,size,"\"\\x%02x\"",(unsigned char)byte);
         | 
| 228 | 
            +
                    break;
         | 
| 229 | 
            +
                }
         | 
| 230 | 
            +
             | 
| 231 | 
            +
                return len;
         | 
| 232 | 
            +
            }
         | 
| 233 | 
            +
             | 
| 234 | 
            +
            static void __redisReaderSetErrorProtocolByte(redisReader *r, char byte) {
         | 
| 235 | 
            +
                char cbuf[8], sbuf[128];
         | 
| 236 | 
            +
             | 
| 237 | 
            +
                chrtos(cbuf,sizeof(cbuf),byte);
         | 
| 238 | 
            +
                snprintf(sbuf,sizeof(sbuf),
         | 
| 239 | 
            +
                    "Protocol error, got %s as reply type byte", cbuf);
         | 
| 240 | 
            +
                __redisReaderSetError(r,REDIS_ERR_PROTOCOL,sbuf);
         | 
| 241 | 
            +
            }
         | 
| 242 | 
            +
             | 
| 243 | 
            +
            static void __redisReaderSetErrorOOM(redisReader *r) {
         | 
| 244 | 
            +
                __redisReaderSetError(r,REDIS_ERR_OOM,"Out of memory");
         | 
| 245 | 
            +
            }
         | 
| 246 | 
            +
             | 
| 161 247 | 
             
            static char *readBytes(redisReader *r, unsigned int bytes) {
         | 
| 162 248 | 
             
                char *p;
         | 
| 163 249 | 
             
                if (r->len-r->pos >= bytes) {
         | 
| @@ -271,22 +357,31 @@ static int processLineItem(redisReader *r) { | |
| 271 357 | 
             
                int len;
         | 
| 272 358 |  | 
| 273 359 | 
             
                if ((p = readLine(r,&len)) != NULL) {
         | 
| 274 | 
            -
                    if ( | 
| 275 | 
            -
                        if ( | 
| 360 | 
            +
                    if (cur->type == REDIS_REPLY_INTEGER) {
         | 
| 361 | 
            +
                        if (r->fn && r->fn->createInteger)
         | 
| 276 362 | 
             
                            obj = r->fn->createInteger(cur,readLongLong(p));
         | 
| 277 | 
            -
                         | 
| 278 | 
            -
                            obj =  | 
| 279 | 
            -
                        }
         | 
| 363 | 
            +
                        else
         | 
| 364 | 
            +
                            obj = (void*)REDIS_REPLY_INTEGER;
         | 
| 280 365 | 
             
                    } else {
         | 
| 281 | 
            -
                         | 
| 366 | 
            +
                        /* Type will be error or status. */
         | 
| 367 | 
            +
                        if (r->fn && r->fn->createString)
         | 
| 368 | 
            +
                            obj = r->fn->createString(cur,p,len);
         | 
| 369 | 
            +
                        else
         | 
| 370 | 
            +
                            obj = (void*)(size_t)(cur->type);
         | 
| 371 | 
            +
                    }
         | 
| 372 | 
            +
             | 
| 373 | 
            +
                    if (obj == NULL) {
         | 
| 374 | 
            +
                        __redisReaderSetErrorOOM(r);
         | 
| 375 | 
            +
                        return REDIS_ERR;
         | 
| 282 376 | 
             
                    }
         | 
| 283 377 |  | 
| 284 378 | 
             
                    /* Set reply if this is the root object. */
         | 
| 285 379 | 
             
                    if (r->ridx == 0) r->reply = obj;
         | 
| 286 380 | 
             
                    moveToNextTask(r);
         | 
| 287 | 
            -
                    return  | 
| 381 | 
            +
                    return REDIS_OK;
         | 
| 288 382 | 
             
                }
         | 
| 289 | 
            -
             | 
| 383 | 
            +
             | 
| 384 | 
            +
                return REDIS_ERR;
         | 
| 290 385 | 
             
            }
         | 
| 291 386 |  | 
| 292 387 | 
             
            static int processBulkItem(redisReader *r) {
         | 
| @@ -306,30 +401,40 @@ static int processBulkItem(redisReader *r) { | |
| 306 401 |  | 
| 307 402 | 
             
                    if (len < 0) {
         | 
| 308 403 | 
             
                        /* The nil object can always be created. */
         | 
| 309 | 
            -
                         | 
| 310 | 
            -
                            ( | 
| 404 | 
            +
                        if (r->fn && r->fn->createNil)
         | 
| 405 | 
            +
                            obj = r->fn->createNil(cur);
         | 
| 406 | 
            +
                        else
         | 
| 407 | 
            +
                            obj = (void*)REDIS_REPLY_NIL;
         | 
| 311 408 | 
             
                        success = 1;
         | 
| 312 409 | 
             
                    } else {
         | 
| 313 410 | 
             
                        /* Only continue when the buffer contains the entire bulk item. */
         | 
| 314 411 | 
             
                        bytelen += len+2; /* include \r\n */
         | 
| 315 412 | 
             
                        if (r->pos+bytelen <= r->len) {
         | 
| 316 | 
            -
                             | 
| 317 | 
            -
                                ( | 
| 413 | 
            +
                            if (r->fn && r->fn->createString)
         | 
| 414 | 
            +
                                obj = r->fn->createString(cur,s+2,len);
         | 
| 415 | 
            +
                            else
         | 
| 416 | 
            +
                                obj = (void*)REDIS_REPLY_STRING;
         | 
| 318 417 | 
             
                            success = 1;
         | 
| 319 418 | 
             
                        }
         | 
| 320 419 | 
             
                    }
         | 
| 321 420 |  | 
| 322 421 | 
             
                    /* Proceed when obj was created. */
         | 
| 323 422 | 
             
                    if (success) {
         | 
| 423 | 
            +
                        if (obj == NULL) {
         | 
| 424 | 
            +
                            __redisReaderSetErrorOOM(r);
         | 
| 425 | 
            +
                            return REDIS_ERR;
         | 
| 426 | 
            +
                        }
         | 
| 427 | 
            +
             | 
| 324 428 | 
             
                        r->pos += bytelen;
         | 
| 325 429 |  | 
| 326 430 | 
             
                        /* Set reply if this is the root object. */
         | 
| 327 431 | 
             
                        if (r->ridx == 0) r->reply = obj;
         | 
| 328 432 | 
             
                        moveToNextTask(r);
         | 
| 329 | 
            -
                        return  | 
| 433 | 
            +
                        return REDIS_OK;
         | 
| 330 434 | 
             
                    }
         | 
| 331 435 | 
             
                }
         | 
| 332 | 
            -
             | 
| 436 | 
            +
             | 
| 437 | 
            +
                return REDIS_ERR;
         | 
| 333 438 | 
             
            }
         | 
| 334 439 |  | 
| 335 440 | 
             
            static int processMultiBulkItem(redisReader *r) {
         | 
| @@ -341,9 +446,9 @@ static int processMultiBulkItem(redisReader *r) { | |
| 341 446 |  | 
| 342 447 | 
             
                /* Set error for nested multi bulks with depth > 1 */
         | 
| 343 448 | 
             
                if (r->ridx == 2) {
         | 
| 344 | 
            -
                     | 
| 345 | 
            -
                        "No support for nested multi bulk replies with depth > 1") | 
| 346 | 
            -
                    return  | 
| 449 | 
            +
                    __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
         | 
| 450 | 
            +
                        "No support for nested multi bulk replies with depth > 1");
         | 
| 451 | 
            +
                    return REDIS_ERR;
         | 
| 347 452 | 
             
                }
         | 
| 348 453 |  | 
| 349 454 | 
             
                if ((p = readLine(r,NULL)) != NULL) {
         | 
| @@ -351,12 +456,27 @@ static int processMultiBulkItem(redisReader *r) { | |
| 351 456 | 
             
                    root = (r->ridx == 0);
         | 
| 352 457 |  | 
| 353 458 | 
             
                    if (elements == -1) {
         | 
| 354 | 
            -
                         | 
| 355 | 
            -
                            ( | 
| 459 | 
            +
                        if (r->fn && r->fn->createNil)
         | 
| 460 | 
            +
                            obj = r->fn->createNil(cur);
         | 
| 461 | 
            +
                        else
         | 
| 462 | 
            +
                            obj = (void*)REDIS_REPLY_NIL;
         | 
| 463 | 
            +
             | 
| 464 | 
            +
                        if (obj == NULL) {
         | 
| 465 | 
            +
                            __redisReaderSetErrorOOM(r);
         | 
| 466 | 
            +
                            return REDIS_ERR;
         | 
| 467 | 
            +
                        }
         | 
| 468 | 
            +
             | 
| 356 469 | 
             
                        moveToNextTask(r);
         | 
| 357 470 | 
             
                    } else {
         | 
| 358 | 
            -
                         | 
| 359 | 
            -
                            ( | 
| 471 | 
            +
                        if (r->fn && r->fn->createArray)
         | 
| 472 | 
            +
                            obj = r->fn->createArray(cur,elements);
         | 
| 473 | 
            +
                        else
         | 
| 474 | 
            +
                            obj = (void*)REDIS_REPLY_ARRAY;
         | 
| 475 | 
            +
             | 
| 476 | 
            +
                        if (obj == NULL) {
         | 
| 477 | 
            +
                            __redisReaderSetErrorOOM(r);
         | 
| 478 | 
            +
                            return REDIS_ERR;
         | 
| 479 | 
            +
                        }
         | 
| 360 480 |  | 
| 361 481 | 
             
                        /* Modify task stack when there are more than 0 elements. */
         | 
| 362 482 | 
             
                        if (elements > 0) {
         | 
| @@ -376,15 +496,15 @@ static int processMultiBulkItem(redisReader *r) { | |
| 376 496 |  | 
| 377 497 | 
             
                    /* Set reply if this is the root object. */
         | 
| 378 498 | 
             
                    if (root) r->reply = obj;
         | 
| 379 | 
            -
                    return  | 
| 499 | 
            +
                    return REDIS_OK;
         | 
| 380 500 | 
             
                }
         | 
| 381 | 
            -
             | 
| 501 | 
            +
             | 
| 502 | 
            +
                return REDIS_ERR;
         | 
| 382 503 | 
             
            }
         | 
| 383 504 |  | 
| 384 505 | 
             
            static int processItem(redisReader *r) {
         | 
| 385 506 | 
             
                redisReadTask *cur = &(r->rstack[r->ridx]);
         | 
| 386 507 | 
             
                char *p;
         | 
| 387 | 
            -
                sds byte;
         | 
| 388 508 |  | 
| 389 509 | 
             
                /* check if we need to read type */
         | 
| 390 510 | 
             
                if (cur->type < 0) {
         | 
| @@ -406,15 +526,12 @@ static int processItem(redisReader *r) { | |
| 406 526 | 
             
                            cur->type = REDIS_REPLY_ARRAY;
         | 
| 407 527 | 
             
                            break;
         | 
| 408 528 | 
             
                        default:
         | 
| 409 | 
            -
                             | 
| 410 | 
            -
                             | 
| 411 | 
            -
                                "Protocol error, got %s as reply type byte", byte));
         | 
| 412 | 
            -
                            sdsfree(byte);
         | 
| 413 | 
            -
                            return -1;
         | 
| 529 | 
            +
                            __redisReaderSetErrorProtocolByte(r,*p);
         | 
| 530 | 
            +
                            return REDIS_ERR;
         | 
| 414 531 | 
             
                        }
         | 
| 415 532 | 
             
                    } else {
         | 
| 416 533 | 
             
                        /* could not consume 1 byte */
         | 
| 417 | 
            -
                        return  | 
| 534 | 
            +
                        return REDIS_ERR;
         | 
| 418 535 | 
             
                    }
         | 
| 419 536 | 
             
                }
         | 
| 420 537 |  | 
| @@ -430,93 +547,78 @@ static int processItem(redisReader *r) { | |
| 430 547 | 
             
                    return processMultiBulkItem(r);
         | 
| 431 548 | 
             
                default:
         | 
| 432 549 | 
             
                    assert(NULL);
         | 
| 433 | 
            -
                    return  | 
| 550 | 
            +
                    return REDIS_ERR; /* Avoid warning. */
         | 
| 434 551 | 
             
                }
         | 
| 435 552 | 
             
            }
         | 
| 436 553 |  | 
| 437 | 
            -
             | 
| 438 | 
            -
                redisReader *r | 
| 439 | 
            -
                r->error = NULL;
         | 
| 440 | 
            -
                r->fn = &defaultFunctions;
         | 
| 441 | 
            -
                r->buf = sdsempty();
         | 
| 442 | 
            -
                r->ridx = -1;
         | 
| 443 | 
            -
                return r;
         | 
| 444 | 
            -
            }
         | 
| 554 | 
            +
            redisReader *redisReaderCreate(void) {
         | 
| 555 | 
            +
                redisReader *r;
         | 
| 445 556 |  | 
| 446 | 
            -
             | 
| 447 | 
            -
              | 
| 448 | 
            -
             | 
| 449 | 
            -
                redisReader *r = reader;
         | 
| 450 | 
            -
                if (r->reply == NULL) {
         | 
| 451 | 
            -
                    r->fn = fn;
         | 
| 452 | 
            -
                    return REDIS_OK;
         | 
| 453 | 
            -
                }
         | 
| 454 | 
            -
                return REDIS_ERR;
         | 
| 455 | 
            -
            }
         | 
| 557 | 
            +
                r = calloc(sizeof(redisReader),1);
         | 
| 558 | 
            +
                if (r == NULL)
         | 
| 559 | 
            +
                    return NULL;
         | 
| 456 560 |  | 
| 457 | 
            -
             | 
| 458 | 
            -
              | 
| 459 | 
            -
             | 
| 460 | 
            -
                 | 
| 461 | 
            -
                if (r-> | 
| 462 | 
            -
                    r | 
| 463 | 
            -
                    return  | 
| 561 | 
            +
                r->err = 0;
         | 
| 562 | 
            +
                r->errstr[0] = '\0';
         | 
| 563 | 
            +
                r->fn = &defaultFunctions;
         | 
| 564 | 
            +
                r->buf = sdsempty();
         | 
| 565 | 
            +
                if (r->buf == NULL) {
         | 
| 566 | 
            +
                    free(r);
         | 
| 567 | 
            +
                    return NULL;
         | 
| 464 568 | 
             
                }
         | 
| 465 | 
            -
                return REDIS_ERR;
         | 
| 466 | 
            -
            }
         | 
| 467 569 |  | 
| 468 | 
            -
             | 
| 469 | 
            -
              | 
| 470 | 
            -
             * object in between receiving some bytes to parse, this object might
         | 
| 471 | 
            -
             * otherwise be free'd by garbage collection. */
         | 
| 472 | 
            -
            void *redisReplyReaderGetObject(void *reader) {
         | 
| 473 | 
            -
                redisReader *r = reader;
         | 
| 474 | 
            -
                return r->reply;
         | 
| 570 | 
            +
                r->ridx = -1;
         | 
| 571 | 
            +
                return r;
         | 
| 475 572 | 
             
            }
         | 
| 476 573 |  | 
| 477 | 
            -
            void  | 
| 478 | 
            -
                 | 
| 479 | 
            -
                if (r->error != NULL)
         | 
| 480 | 
            -
                    sdsfree(r->error);
         | 
| 481 | 
            -
                if (r->reply != NULL && r->fn)
         | 
| 574 | 
            +
            void redisReaderFree(redisReader *r) {
         | 
| 575 | 
            +
                if (r->reply != NULL && r->fn && r->fn->freeObject)
         | 
| 482 576 | 
             
                    r->fn->freeObject(r->reply);
         | 
| 483 577 | 
             
                if (r->buf != NULL)
         | 
| 484 578 | 
             
                    sdsfree(r->buf);
         | 
| 485 579 | 
             
                free(r);
         | 
| 486 580 | 
             
            }
         | 
| 487 581 |  | 
| 488 | 
            -
             | 
| 489 | 
            -
                 | 
| 490 | 
            -
                    r->fn->freeObject(r->reply);
         | 
| 582 | 
            +
            int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
         | 
| 583 | 
            +
                sds newbuf;
         | 
| 491 584 |  | 
| 492 | 
            -
                /*  | 
| 493 | 
            -
                if (r-> | 
| 494 | 
            -
                     | 
| 495 | 
            -
                    r->buf = sdsempty();
         | 
| 496 | 
            -
                    r->pos = r->len = 0;
         | 
| 497 | 
            -
                }
         | 
| 498 | 
            -
                r->ridx = -1;
         | 
| 499 | 
            -
                r->error = err;
         | 
| 500 | 
            -
            }
         | 
| 501 | 
            -
             | 
| 502 | 
            -
            char *redisReplyReaderGetError(void *reader) {
         | 
| 503 | 
            -
                redisReader *r = reader;
         | 
| 504 | 
            -
                return r->error;
         | 
| 505 | 
            -
            }
         | 
| 506 | 
            -
             | 
| 507 | 
            -
            void redisReplyReaderFeed(void *reader, const char *buf, size_t len) {
         | 
| 508 | 
            -
                redisReader *r = reader;
         | 
| 585 | 
            +
                /* Return early when this reader is in an erroneous state. */
         | 
| 586 | 
            +
                if (r->err)
         | 
| 587 | 
            +
                    return REDIS_ERR;
         | 
| 509 588 |  | 
| 510 589 | 
             
                /* Copy the provided buffer. */
         | 
| 511 590 | 
             
                if (buf != NULL && len >= 1) {
         | 
| 512 | 
            -
                     | 
| 591 | 
            +
                    /* Destroy internal buffer when it is empty and is quite large. */
         | 
| 592 | 
            +
                    if (r->len == 0 && sdsavail(r->buf) > 16*1024) {
         | 
| 593 | 
            +
                        sdsfree(r->buf);
         | 
| 594 | 
            +
                        r->buf = sdsempty();
         | 
| 595 | 
            +
                        r->pos = 0;
         | 
| 596 | 
            +
             | 
| 597 | 
            +
                        /* r->buf should not be NULL since we just free'd a larger one. */
         | 
| 598 | 
            +
                        assert(r->buf != NULL);
         | 
| 599 | 
            +
                    }
         | 
| 600 | 
            +
             | 
| 601 | 
            +
                    newbuf = sdscatlen(r->buf,buf,len);
         | 
| 602 | 
            +
                    if (newbuf == NULL) {
         | 
| 603 | 
            +
                        __redisReaderSetErrorOOM(r);
         | 
| 604 | 
            +
                        return REDIS_ERR;
         | 
| 605 | 
            +
                    }
         | 
| 606 | 
            +
             | 
| 607 | 
            +
                    r->buf = newbuf;
         | 
| 513 608 | 
             
                    r->len = sdslen(r->buf);
         | 
| 514 609 | 
             
                }
         | 
| 610 | 
            +
             | 
| 611 | 
            +
                return REDIS_OK;
         | 
| 515 612 | 
             
            }
         | 
| 516 613 |  | 
| 517 | 
            -
            int  | 
| 518 | 
            -
                 | 
| 519 | 
            -
                if (reply != NULL) | 
| 614 | 
            +
            int redisReaderGetReply(redisReader *r, void **reply) {
         | 
| 615 | 
            +
                /* Default target pointer to NULL. */
         | 
| 616 | 
            +
                if (reply != NULL)
         | 
| 617 | 
            +
                    *reply = NULL;
         | 
| 618 | 
            +
             | 
| 619 | 
            +
                /* Return early when this reader is in an erroneous state. */
         | 
| 620 | 
            +
                if (r->err)
         | 
| 621 | 
            +
                    return REDIS_ERR;
         | 
| 520 622 |  | 
| 521 623 | 
             
                /* When the buffer is empty, there will never be a reply. */
         | 
| 522 624 | 
             
                if (r->len == 0)
         | 
| @@ -535,9 +637,13 @@ int redisReplyReaderGetReply(void *reader, void **reply) { | |
| 535 637 |  | 
| 536 638 | 
             
                /* Process items in reply. */
         | 
| 537 639 | 
             
                while (r->ridx >= 0)
         | 
| 538 | 
            -
                    if (processItem(r)  | 
| 640 | 
            +
                    if (processItem(r) != REDIS_OK)
         | 
| 539 641 | 
             
                        break;
         | 
| 540 642 |  | 
| 643 | 
            +
                /* Return ASAP when an error occurred. */
         | 
| 644 | 
            +
                if (r->err)
         | 
| 645 | 
            +
                    return REDIS_ERR;
         | 
| 646 | 
            +
             | 
| 541 647 | 
             
                /* Discard part of the buffer when we've consumed at least 1k, to avoid
         | 
| 542 648 | 
             
                 * doing unnecessary calls to memmove() in sds.c. */
         | 
| 543 649 | 
             
                if (r->pos >= 1024) {
         | 
| @@ -548,22 +654,9 @@ int redisReplyReaderGetReply(void *reader, void **reply) { | |
| 548 654 |  | 
| 549 655 | 
             
                /* Emit a reply when there is one. */
         | 
| 550 656 | 
             
                if (r->ridx == -1) {
         | 
| 551 | 
            -
                     | 
| 657 | 
            +
                    if (reply != NULL)
         | 
| 658 | 
            +
                        *reply = r->reply;
         | 
| 552 659 | 
             
                    r->reply = NULL;
         | 
| 553 | 
            -
             | 
| 554 | 
            -
                    /* Destroy the buffer when it is empty and is quite large. */
         | 
| 555 | 
            -
                    if (r->len == 0 && sdsavail(r->buf) > 16*1024) {
         | 
| 556 | 
            -
                        sdsfree(r->buf);
         | 
| 557 | 
            -
                        r->buf = sdsempty();
         | 
| 558 | 
            -
                        r->pos = 0;
         | 
| 559 | 
            -
                    }
         | 
| 560 | 
            -
             | 
| 561 | 
            -
                    /* Check if there actually *is* a reply. */
         | 
| 562 | 
            -
                    if (r->error != NULL) {
         | 
| 563 | 
            -
                        return REDIS_ERR;
         | 
| 564 | 
            -
                    } else {
         | 
| 565 | 
            -
                        if (reply != NULL) *reply = aux;
         | 
| 566 | 
            -
                    }
         | 
| 567 660 | 
             
                }
         | 
| 568 661 | 
             
                return REDIS_OK;
         | 
| 569 662 | 
             
            }
         | 
| @@ -582,60 +675,74 @@ static int intlen(int i) { | |
| 582 675 | 
             
                return len;
         | 
| 583 676 | 
             
            }
         | 
| 584 677 |  | 
| 585 | 
            -
            /* Helper  | 
| 586 | 
            -
            static  | 
| 587 | 
            -
                ( | 
| 588 | 
            -
                if ((*argv = realloc(*argv, sizeof(char*)*(*argc))) == NULL) redisOOM();
         | 
| 589 | 
            -
                if (totlen) *totlen = *totlen+1+intlen(sdslen(a))+2+sdslen(a)+2;
         | 
| 590 | 
            -
                (*argv)[(*argc)-1] = a;
         | 
| 678 | 
            +
            /* Helper that calculates the bulk length given a certain string length. */
         | 
| 679 | 
            +
            static size_t bulklen(size_t len) {
         | 
| 680 | 
            +
                return 1+intlen(len)+2+len+2;
         | 
| 591 681 | 
             
            }
         | 
| 592 682 |  | 
| 593 683 | 
             
            int redisvFormatCommand(char **target, const char *format, va_list ap) {
         | 
| 594 | 
            -
                 | 
| 595 | 
            -
                const char *arg, *c = format;
         | 
| 684 | 
            +
                const char *c = format;
         | 
| 596 685 | 
             
                char *cmd = NULL; /* final command */
         | 
| 597 686 | 
             
                int pos; /* position in final command */
         | 
| 598 | 
            -
                sds  | 
| 599 | 
            -
                int  | 
| 600 | 
            -
                char ** | 
| 601 | 
            -
                int argc = 0 | 
| 687 | 
            +
                sds curarg, newarg; /* current argument */
         | 
| 688 | 
            +
                int touched = 0; /* was the current argument touched? */
         | 
| 689 | 
            +
                char **curargv = NULL, **newargv = NULL;
         | 
| 690 | 
            +
                int argc = 0;
         | 
| 602 691 | 
             
                int totlen = 0;
         | 
| 692 | 
            +
                int j;
         | 
| 603 693 |  | 
| 604 694 | 
             
                /* Abort if there is not target to set */
         | 
| 605 695 | 
             
                if (target == NULL)
         | 
| 606 696 | 
             
                    return -1;
         | 
| 607 697 |  | 
| 608 698 | 
             
                /* Build the command string accordingly to protocol */
         | 
| 609 | 
            -
                 | 
| 699 | 
            +
                curarg = sdsempty();
         | 
| 700 | 
            +
                if (curarg == NULL)
         | 
| 701 | 
            +
                    return -1;
         | 
| 702 | 
            +
             | 
| 610 703 | 
             
                while(*c != '\0') {
         | 
| 611 704 | 
             
                    if (*c != '%' || c[1] == '\0') {
         | 
| 612 705 | 
             
                        if (*c == ' ') {
         | 
| 613 | 
            -
                            if ( | 
| 614 | 
            -
                                 | 
| 615 | 
            -
                                 | 
| 616 | 
            -
                                 | 
| 706 | 
            +
                            if (touched) {
         | 
| 707 | 
            +
                                newargv = realloc(curargv,sizeof(char*)*(argc+1));
         | 
| 708 | 
            +
                                if (newargv == NULL) goto err;
         | 
| 709 | 
            +
                                curargv = newargv;
         | 
| 710 | 
            +
                                curargv[argc++] = curarg;
         | 
| 711 | 
            +
                                totlen += bulklen(sdslen(curarg));
         | 
| 712 | 
            +
             | 
| 713 | 
            +
                                /* curarg is put in argv so it can be overwritten. */
         | 
| 714 | 
            +
                                curarg = sdsempty();
         | 
| 715 | 
            +
                                if (curarg == NULL) goto err;
         | 
| 716 | 
            +
                                touched = 0;
         | 
| 617 717 | 
             
                            }
         | 
| 618 718 | 
             
                        } else {
         | 
| 619 | 
            -
                             | 
| 719 | 
            +
                            newarg = sdscatlen(curarg,c,1);
         | 
| 720 | 
            +
                            if (newarg == NULL) goto err;
         | 
| 721 | 
            +
                            curarg = newarg;
         | 
| 722 | 
            +
                            touched = 1;
         | 
| 620 723 | 
             
                        }
         | 
| 621 724 | 
             
                    } else {
         | 
| 725 | 
            +
                        char *arg;
         | 
| 726 | 
            +
                        size_t size;
         | 
| 727 | 
            +
             | 
| 728 | 
            +
                        /* Set newarg so it can be checked even if it is not touched. */
         | 
| 729 | 
            +
                        newarg = curarg;
         | 
| 730 | 
            +
             | 
| 622 731 | 
             
                        switch(c[1]) {
         | 
| 623 732 | 
             
                        case 's':
         | 
| 624 733 | 
             
                            arg = va_arg(ap,char*);
         | 
| 625 734 | 
             
                            size = strlen(arg);
         | 
| 626 735 | 
             
                            if (size > 0)
         | 
| 627 | 
            -
                                 | 
| 628 | 
            -
                            interpolated = 1;
         | 
| 736 | 
            +
                                newarg = sdscatlen(curarg,arg,size);
         | 
| 629 737 | 
             
                            break;
         | 
| 630 738 | 
             
                        case 'b':
         | 
| 631 739 | 
             
                            arg = va_arg(ap,char*);
         | 
| 632 740 | 
             
                            size = va_arg(ap,size_t);
         | 
| 633 741 | 
             
                            if (size > 0)
         | 
| 634 | 
            -
                                 | 
| 635 | 
            -
                            interpolated = 1;
         | 
| 742 | 
            +
                                newarg = sdscatlen(curarg,arg,size);
         | 
| 636 743 | 
             
                            break;
         | 
| 637 744 | 
             
                        case '%':
         | 
| 638 | 
            -
                             | 
| 745 | 
            +
                            newarg = sdscat(curarg,"%");
         | 
| 639 746 | 
             
                            break;
         | 
| 640 747 | 
             
                        default:
         | 
| 641 748 | 
             
                            /* Try to detect printf format */
         | 
| @@ -677,8 +784,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) { | |
| 677 784 | 
             
                                        memcpy(_format,c,_l);
         | 
| 678 785 | 
             
                                        _format[_l] = '\0';
         | 
| 679 786 | 
             
                                        va_copy(_cpy,ap);
         | 
| 680 | 
            -
                                         | 
| 681 | 
            -
                                        interpolated = 1;
         | 
| 787 | 
            +
                                        newarg = sdscatvprintf(curarg,_format,_cpy);
         | 
| 682 788 | 
             
                                        va_end(_cpy);
         | 
| 683 789 |  | 
| 684 790 | 
             
                                        /* Update current position (note: outer blocks
         | 
| @@ -691,38 +797,67 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) { | |
| 691 797 | 
             
                                va_arg(ap,void);
         | 
| 692 798 | 
             
                            }
         | 
| 693 799 | 
             
                        }
         | 
| 800 | 
            +
             | 
| 801 | 
            +
                        if (newarg == NULL) goto err;
         | 
| 802 | 
            +
                        curarg = newarg;
         | 
| 803 | 
            +
             | 
| 804 | 
            +
                        touched = 1;
         | 
| 694 805 | 
             
                        c++;
         | 
| 695 806 | 
             
                    }
         | 
| 696 807 | 
             
                    c++;
         | 
| 697 808 | 
             
                }
         | 
| 698 809 |  | 
| 699 810 | 
             
                /* Add the last argument if needed */
         | 
| 700 | 
            -
                if ( | 
| 701 | 
            -
                     | 
| 811 | 
            +
                if (touched) {
         | 
| 812 | 
            +
                    newargv = realloc(curargv,sizeof(char*)*(argc+1));
         | 
| 813 | 
            +
                    if (newargv == NULL) goto err;
         | 
| 814 | 
            +
                    curargv = newargv;
         | 
| 815 | 
            +
                    curargv[argc++] = curarg;
         | 
| 816 | 
            +
                    totlen += bulklen(sdslen(curarg));
         | 
| 702 817 | 
             
                } else {
         | 
| 703 | 
            -
                    sdsfree( | 
| 818 | 
            +
                    sdsfree(curarg);
         | 
| 704 819 | 
             
                }
         | 
| 705 820 |  | 
| 821 | 
            +
                /* Clear curarg because it was put in curargv or was free'd. */
         | 
| 822 | 
            +
                curarg = NULL;
         | 
| 823 | 
            +
             | 
| 706 824 | 
             
                /* Add bytes needed to hold multi bulk count */
         | 
| 707 825 | 
             
                totlen += 1+intlen(argc)+2;
         | 
| 708 826 |  | 
| 709 827 | 
             
                /* Build the command at protocol level */
         | 
| 710 828 | 
             
                cmd = malloc(totlen+1);
         | 
| 711 | 
            -
                if ( | 
| 829 | 
            +
                if (cmd == NULL) goto err;
         | 
| 830 | 
            +
             | 
| 712 831 | 
             
                pos = sprintf(cmd,"*%d\r\n",argc);
         | 
| 713 832 | 
             
                for (j = 0; j < argc; j++) {
         | 
| 714 | 
            -
                    pos += sprintf(cmd+pos,"$%zu\r\n",sdslen( | 
| 715 | 
            -
                    memcpy(cmd+pos, | 
| 716 | 
            -
                    pos += sdslen( | 
| 717 | 
            -
                    sdsfree( | 
| 833 | 
            +
                    pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j]));
         | 
| 834 | 
            +
                    memcpy(cmd+pos,curargv[j],sdslen(curargv[j]));
         | 
| 835 | 
            +
                    pos += sdslen(curargv[j]);
         | 
| 836 | 
            +
                    sdsfree(curargv[j]);
         | 
| 718 837 | 
             
                    cmd[pos++] = '\r';
         | 
| 719 838 | 
             
                    cmd[pos++] = '\n';
         | 
| 720 839 | 
             
                }
         | 
| 721 840 | 
             
                assert(pos == totlen);
         | 
| 722 | 
            -
                 | 
| 723 | 
            -
             | 
| 841 | 
            +
                cmd[pos] = '\0';
         | 
| 842 | 
            +
             | 
| 843 | 
            +
                free(curargv);
         | 
| 724 844 | 
             
                *target = cmd;
         | 
| 725 845 | 
             
                return totlen;
         | 
| 846 | 
            +
             | 
| 847 | 
            +
            err:
         | 
| 848 | 
            +
                while(argc--)
         | 
| 849 | 
            +
                    sdsfree(curargv[argc]);
         | 
| 850 | 
            +
                free(curargv);
         | 
| 851 | 
            +
             | 
| 852 | 
            +
                if (curarg != NULL)
         | 
| 853 | 
            +
                    sdsfree(curarg);
         | 
| 854 | 
            +
             | 
| 855 | 
            +
                /* No need to check cmd since it is the last statement that can fail,
         | 
| 856 | 
            +
                 * but do it anyway to be as defensive as possible. */
         | 
| 857 | 
            +
                if (cmd != NULL)
         | 
| 858 | 
            +
                    free(cmd);
         | 
| 859 | 
            +
             | 
| 860 | 
            +
                return -1;
         | 
| 726 861 | 
             
            }
         | 
| 727 862 |  | 
| 728 863 | 
             
            /* Format a command according to the Redis protocol. This function
         | 
| @@ -761,12 +896,14 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz | |
| 761 896 | 
             
                totlen = 1+intlen(argc)+2;
         | 
| 762 897 | 
             
                for (j = 0; j < argc; j++) {
         | 
| 763 898 | 
             
                    len = argvlen ? argvlen[j] : strlen(argv[j]);
         | 
| 764 | 
            -
                    totlen +=  | 
| 899 | 
            +
                    totlen += bulklen(len);
         | 
| 765 900 | 
             
                }
         | 
| 766 901 |  | 
| 767 902 | 
             
                /* Build the command at protocol level */
         | 
| 768 903 | 
             
                cmd = malloc(totlen+1);
         | 
| 769 | 
            -
                if ( | 
| 904 | 
            +
                if (cmd == NULL)
         | 
| 905 | 
            +
                    return -1;
         | 
| 906 | 
            +
             | 
| 770 907 | 
             
                pos = sprintf(cmd,"*%d\r\n",argc);
         | 
| 771 908 | 
             
                for (j = 0; j < argc; j++) {
         | 
| 772 909 | 
             
                    len = argvlen ? argvlen[j] : strlen(argv[j]);
         | 
| @@ -777,41 +914,49 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz | |
| 777 914 | 
             
                    cmd[pos++] = '\n';
         | 
| 778 915 | 
             
                }
         | 
| 779 916 | 
             
                assert(pos == totlen);
         | 
| 780 | 
            -
                cmd[ | 
| 917 | 
            +
                cmd[pos] = '\0';
         | 
| 918 | 
            +
             | 
| 781 919 | 
             
                *target = cmd;
         | 
| 782 920 | 
             
                return totlen;
         | 
| 783 921 | 
             
            }
         | 
| 784 922 |  | 
| 785 | 
            -
            void __redisSetError(redisContext *c, int type, const  | 
| 923 | 
            +
            void __redisSetError(redisContext *c, int type, const char *str) {
         | 
| 924 | 
            +
                size_t len;
         | 
| 925 | 
            +
             | 
| 786 926 | 
             
                c->err = type;
         | 
| 787 | 
            -
                if ( | 
| 788 | 
            -
                     | 
| 927 | 
            +
                if (str != NULL) {
         | 
| 928 | 
            +
                    len = strlen(str);
         | 
| 929 | 
            +
                    len = len < (sizeof(c->errstr)-1) ? len : (sizeof(c->errstr)-1);
         | 
| 930 | 
            +
                    memcpy(c->errstr,str,len);
         | 
| 931 | 
            +
                    c->errstr[len] = '\0';
         | 
| 789 932 | 
             
                } else {
         | 
| 790 933 | 
             
                    /* Only REDIS_ERR_IO may lack a description! */
         | 
| 791 934 | 
             
                    assert(type == REDIS_ERR_IO);
         | 
| 792 | 
            -
                    c->errstr | 
| 935 | 
            +
                    strerror_r(errno,c->errstr,sizeof(c->errstr));
         | 
| 793 936 | 
             
                }
         | 
| 794 937 | 
             
            }
         | 
| 795 938 |  | 
| 796 939 | 
             
            static redisContext *redisContextInit(void) {
         | 
| 797 | 
            -
                redisContext *c | 
| 940 | 
            +
                redisContext *c;
         | 
| 941 | 
            +
             | 
| 942 | 
            +
                c = calloc(1,sizeof(redisContext));
         | 
| 943 | 
            +
                if (c == NULL)
         | 
| 944 | 
            +
                    return NULL;
         | 
| 945 | 
            +
             | 
| 798 946 | 
             
                c->err = 0;
         | 
| 799 | 
            -
                c->errstr =  | 
| 947 | 
            +
                c->errstr[0] = '\0';
         | 
| 800 948 | 
             
                c->obuf = sdsempty();
         | 
| 801 | 
            -
                c-> | 
| 802 | 
            -
                c->reader = NULL;
         | 
| 949 | 
            +
                c->reader = redisReaderCreate();
         | 
| 803 950 | 
             
                return c;
         | 
| 804 951 | 
             
            }
         | 
| 805 952 |  | 
| 806 953 | 
             
            void redisFree(redisContext *c) {
         | 
| 807 954 | 
             
                if (c->fd > 0)
         | 
| 808 955 | 
             
                    close(c->fd);
         | 
| 809 | 
            -
                if (c->errstr != NULL)
         | 
| 810 | 
            -
                    sdsfree(c->errstr);
         | 
| 811 956 | 
             
                if (c->obuf != NULL)
         | 
| 812 957 | 
             
                    sdsfree(c->obuf);
         | 
| 813 958 | 
             
                if (c->reader != NULL)
         | 
| 814 | 
            -
                     | 
| 959 | 
            +
                    redisReaderFree(c->reader);
         | 
| 815 960 | 
             
                free(c);
         | 
| 816 961 | 
             
            }
         | 
| 817 962 |  | 
| @@ -867,24 +1012,6 @@ int redisSetTimeout(redisContext *c, struct timeval tv) { | |
| 867 1012 | 
             
                return REDIS_ERR;
         | 
| 868 1013 | 
             
            }
         | 
| 869 1014 |  | 
| 870 | 
            -
            /* Set the replyObjectFunctions to use. Returns REDIS_ERR when the reader
         | 
| 871 | 
            -
             * was already initialized and the function set could not be re-set.
         | 
| 872 | 
            -
             * Return REDIS_OK when they could be set. */
         | 
| 873 | 
            -
            int redisSetReplyObjectFunctions(redisContext *c, redisReplyObjectFunctions *fn) {
         | 
| 874 | 
            -
                if (c->reader != NULL)
         | 
| 875 | 
            -
                    return REDIS_ERR;
         | 
| 876 | 
            -
                c->fn = fn;
         | 
| 877 | 
            -
                return REDIS_OK;
         | 
| 878 | 
            -
            }
         | 
| 879 | 
            -
             | 
| 880 | 
            -
            /* Helper function to lazily create a reply reader. */
         | 
| 881 | 
            -
            static void __redisCreateReplyReader(redisContext *c) {
         | 
| 882 | 
            -
                if (c->reader == NULL) {
         | 
| 883 | 
            -
                    c->reader = redisReplyReaderCreate();
         | 
| 884 | 
            -
                    assert(redisReplyReaderSetReplyObjectFunctions(c->reader,c->fn) == REDIS_OK);
         | 
| 885 | 
            -
                }
         | 
| 886 | 
            -
            }
         | 
| 887 | 
            -
             | 
| 888 1015 | 
             
            /* Use this function to handle a read event on the descriptor. It will try
         | 
| 889 1016 | 
             
             * and read some bytes from the socket and feed them to the reply parser.
         | 
| 890 1017 | 
             
             *
         | 
| @@ -892,7 +1019,13 @@ static void __redisCreateReplyReader(redisContext *c) { | |
| 892 1019 | 
             
             * see if there is a reply available. */
         | 
| 893 1020 | 
             
            int redisBufferRead(redisContext *c) {
         | 
| 894 1021 | 
             
                char buf[2048];
         | 
| 895 | 
            -
                int nread | 
| 1022 | 
            +
                int nread;
         | 
| 1023 | 
            +
             | 
| 1024 | 
            +
                /* Return early when the context has seen an error. */
         | 
| 1025 | 
            +
                if (c->err)
         | 
| 1026 | 
            +
                    return REDIS_ERR;
         | 
| 1027 | 
            +
             | 
| 1028 | 
            +
                nread = read(c->fd,buf,sizeof(buf));
         | 
| 896 1029 | 
             
                if (nread == -1) {
         | 
| 897 1030 | 
             
                    if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
         | 
| 898 1031 | 
             
                        /* Try again later */
         | 
| @@ -901,12 +1034,13 @@ int redisBufferRead(redisContext *c) { | |
| 901 1034 | 
             
                        return REDIS_ERR;
         | 
| 902 1035 | 
             
                    }
         | 
| 903 1036 | 
             
                } else if (nread == 0) {
         | 
| 904 | 
            -
                    __redisSetError(c,REDIS_ERR_EOF,
         | 
| 905 | 
            -
                        sdsnew("Server closed the connection"));
         | 
| 1037 | 
            +
                    __redisSetError(c,REDIS_ERR_EOF,"Server closed the connection");
         | 
| 906 1038 | 
             
                    return REDIS_ERR;
         | 
| 907 1039 | 
             
                } else {
         | 
| 908 | 
            -
                     | 
| 909 | 
            -
             | 
| 1040 | 
            +
                    if (redisReaderFeed(c->reader,buf,nread) != REDIS_OK) {
         | 
| 1041 | 
            +
                        __redisSetError(c,c->reader->err,c->reader->errstr);
         | 
| 1042 | 
            +
                        return REDIS_ERR;
         | 
| 1043 | 
            +
                    }
         | 
| 910 1044 | 
             
                }
         | 
| 911 1045 | 
             
                return REDIS_OK;
         | 
| 912 1046 | 
             
            }
         | 
| @@ -922,6 +1056,11 @@ int redisBufferRead(redisContext *c) { | |
| 922 1056 | 
             
             */
         | 
| 923 1057 | 
             
            int redisBufferWrite(redisContext *c, int *done) {
         | 
| 924 1058 | 
             
                int nwritten;
         | 
| 1059 | 
            +
             | 
| 1060 | 
            +
                /* Return early when the context has seen an error. */
         | 
| 1061 | 
            +
                if (c->err)
         | 
| 1062 | 
            +
                    return REDIS_ERR;
         | 
| 1063 | 
            +
             | 
| 925 1064 | 
             
                if (sdslen(c->obuf) > 0) {
         | 
| 926 1065 | 
             
                    nwritten = write(c->fd,c->obuf,sdslen(c->obuf));
         | 
| 927 1066 | 
             
                    if (nwritten == -1) {
         | 
| @@ -947,10 +1086,8 @@ int redisBufferWrite(redisContext *c, int *done) { | |
| 947 1086 | 
             
            /* Internal helper function to try and get a reply from the reader,
         | 
| 948 1087 | 
             
             * or set an error in the context otherwise. */
         | 
| 949 1088 | 
             
            int redisGetReplyFromReader(redisContext *c, void **reply) {
         | 
| 950 | 
            -
                 | 
| 951 | 
            -
             | 
| 952 | 
            -
                    __redisSetError(c,REDIS_ERR_PROTOCOL,
         | 
| 953 | 
            -
                        sdsnew(((redisReader*)c->reader)->error));
         | 
| 1089 | 
            +
                if (redisReaderGetReply(c->reader,reply) == REDIS_ERR) {
         | 
| 1090 | 
            +
                    __redisSetError(c,c->reader->err,c->reader->errstr);
         | 
| 954 1091 | 
             
                    return REDIS_ERR;
         | 
| 955 1092 | 
             
                }
         | 
| 956 1093 | 
             
                return REDIS_OK;
         | 
| @@ -993,31 +1130,65 @@ int redisGetReply(redisContext *c, void **reply) { | |
| 993 1130 | 
             
             * is used, you need to call redisGetReply yourself to retrieve
         | 
| 994 1131 | 
             
             * the reply (or replies in pub/sub).
         | 
| 995 1132 | 
             
             */
         | 
| 996 | 
            -
             | 
| 997 | 
            -
                 | 
| 1133 | 
            +
            int __redisAppendCommand(redisContext *c, char *cmd, size_t len) {
         | 
| 1134 | 
            +
                sds newbuf;
         | 
| 1135 | 
            +
             | 
| 1136 | 
            +
                newbuf = sdscatlen(c->obuf,cmd,len);
         | 
| 1137 | 
            +
                if (newbuf == NULL) {
         | 
| 1138 | 
            +
                    __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
         | 
| 1139 | 
            +
                    return REDIS_ERR;
         | 
| 1140 | 
            +
                }
         | 
| 1141 | 
            +
             | 
| 1142 | 
            +
                c->obuf = newbuf;
         | 
| 1143 | 
            +
                return REDIS_OK;
         | 
| 998 1144 | 
             
            }
         | 
| 999 1145 |  | 
| 1000 | 
            -
             | 
| 1146 | 
            +
            int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
         | 
| 1001 1147 | 
             
                char *cmd;
         | 
| 1002 1148 | 
             
                int len;
         | 
| 1149 | 
            +
             | 
| 1003 1150 | 
             
                len = redisvFormatCommand(&cmd,format,ap);
         | 
| 1004 | 
            -
                 | 
| 1151 | 
            +
                if (len == -1) {
         | 
| 1152 | 
            +
                    __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
         | 
| 1153 | 
            +
                    return REDIS_ERR;
         | 
| 1154 | 
            +
                }
         | 
| 1155 | 
            +
             | 
| 1156 | 
            +
                if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
         | 
| 1157 | 
            +
                    free(cmd);
         | 
| 1158 | 
            +
                    return REDIS_ERR;
         | 
| 1159 | 
            +
                }
         | 
| 1160 | 
            +
             | 
| 1005 1161 | 
             
                free(cmd);
         | 
| 1162 | 
            +
                return REDIS_OK;
         | 
| 1006 1163 | 
             
            }
         | 
| 1007 1164 |  | 
| 1008 | 
            -
             | 
| 1165 | 
            +
            int redisAppendCommand(redisContext *c, const char *format, ...) {
         | 
| 1009 1166 | 
             
                va_list ap;
         | 
| 1167 | 
            +
                int ret;
         | 
| 1168 | 
            +
             | 
| 1010 1169 | 
             
                va_start(ap,format);
         | 
| 1011 | 
            -
                redisvAppendCommand(c,format,ap);
         | 
| 1170 | 
            +
                ret = redisvAppendCommand(c,format,ap);
         | 
| 1012 1171 | 
             
                va_end(ap);
         | 
| 1172 | 
            +
                return ret;
         | 
| 1013 1173 | 
             
            }
         | 
| 1014 1174 |  | 
| 1015 | 
            -
             | 
| 1175 | 
            +
            int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
         | 
| 1016 1176 | 
             
                char *cmd;
         | 
| 1017 1177 | 
             
                int len;
         | 
| 1178 | 
            +
             | 
| 1018 1179 | 
             
                len = redisFormatCommandArgv(&cmd,argc,argv,argvlen);
         | 
| 1019 | 
            -
                 | 
| 1180 | 
            +
                if (len == -1) {
         | 
| 1181 | 
            +
                    __redisSetError(c,REDIS_ERR_OOM,"Out of memory");
         | 
| 1182 | 
            +
                    return REDIS_ERR;
         | 
| 1183 | 
            +
                }
         | 
| 1184 | 
            +
             | 
| 1185 | 
            +
                if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {
         | 
| 1186 | 
            +
                    free(cmd);
         | 
| 1187 | 
            +
                    return REDIS_ERR;
         | 
| 1188 | 
            +
                }
         | 
| 1189 | 
            +
             | 
| 1020 1190 | 
             
                free(cmd);
         | 
| 1191 | 
            +
                return REDIS_OK;
         | 
| 1021 1192 | 
             
            }
         | 
| 1022 1193 |  | 
| 1023 1194 | 
             
            /* Helper function for the redisCommand* family of functions.
         | 
| @@ -1031,26 +1202,21 @@ void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const | |
| 1031 1202 | 
             
             * otherwise. When NULL is returned in a blocking context, the error field
         | 
| 1032 1203 | 
             
             * in the context will be set.
         | 
| 1033 1204 | 
             
             */
         | 
| 1034 | 
            -
            static void * | 
| 1035 | 
            -
                void * | 
| 1036 | 
            -
                __redisAppendCommand(c,cmd,len);
         | 
| 1205 | 
            +
            static void *__redisBlockForReply(redisContext *c) {
         | 
| 1206 | 
            +
                void *reply;
         | 
| 1037 1207 |  | 
| 1038 1208 | 
             
                if (c->flags & REDIS_BLOCK) {
         | 
| 1039 | 
            -
                    if (redisGetReply(c,& | 
| 1040 | 
            -
                        return  | 
| 1041 | 
            -
                    return  | 
| 1209 | 
            +
                    if (redisGetReply(c,&reply) != REDIS_OK)
         | 
| 1210 | 
            +
                        return NULL;
         | 
| 1211 | 
            +
                    return reply;
         | 
| 1042 1212 | 
             
                }
         | 
| 1043 1213 | 
             
                return NULL;
         | 
| 1044 1214 | 
             
            }
         | 
| 1045 1215 |  | 
| 1046 1216 | 
             
            void *redisvCommand(redisContext *c, const char *format, va_list ap) {
         | 
| 1047 | 
            -
                 | 
| 1048 | 
            -
             | 
| 1049 | 
            -
                 | 
| 1050 | 
            -
                len = redisvFormatCommand(&cmd,format,ap);
         | 
| 1051 | 
            -
                reply = __redisCommand(c,cmd,len);
         | 
| 1052 | 
            -
                free(cmd);
         | 
| 1053 | 
            -
                return reply;
         | 
| 1217 | 
            +
                if (redisvAppendCommand(c,format,ap) != REDIS_OK)
         | 
| 1218 | 
            +
                    return NULL;
         | 
| 1219 | 
            +
                return __redisBlockForReply(c);
         | 
| 1054 1220 | 
             
            }
         | 
| 1055 1221 |  | 
| 1056 1222 | 
             
            void *redisCommand(redisContext *c, const char *format, ...) {
         | 
| @@ -1063,11 +1229,7 @@ void *redisCommand(redisContext *c, const char *format, ...) { | |
| 1063 1229 | 
             
            }
         | 
| 1064 1230 |  | 
| 1065 1231 | 
             
            void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {
         | 
| 1066 | 
            -
                 | 
| 1067 | 
            -
             | 
| 1068 | 
            -
                 | 
| 1069 | 
            -
                len = redisFormatCommandArgv(&cmd,argc,argv,argvlen);
         | 
| 1070 | 
            -
                reply = __redisCommand(c,cmd,len);
         | 
| 1071 | 
            -
                free(cmd);
         | 
| 1072 | 
            -
                return reply;
         | 
| 1232 | 
            +
                if (redisAppendCommandArgv(c,argc,argv,argvlen) != REDIS_OK)
         | 
| 1233 | 
            +
                    return NULL;
         | 
| 1234 | 
            +
                return __redisBlockForReply(c);
         | 
| 1073 1235 | 
             
            }
         |