2 * Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
3 * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
10 * * Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Redis nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
44 typedef struct redisReader
{
45 struct redisReplyObjectFunctions
*fn
;
46 sds error
; /* holds optional error */
47 void *reply
; /* holds temporary reply */
49 sds buf
; /* read buffer */
50 size_t pos
; /* buffer cursor */
51 size_t len
; /* buffer length */
53 redisReadTask rstack
[3]; /* stack of read tasks */
54 int ridx
; /* index of stack */
55 void *privdata
; /* user-settable arbitrary field */
58 static redisReply
*createReplyObject(int type
);
59 static void *createStringObject(const redisReadTask
*task
, char *str
, size_t len
);
60 static void *createArrayObject(const redisReadTask
*task
, int elements
);
61 static void *createIntegerObject(const redisReadTask
*task
, long long value
);
62 static void *createNilObject(const redisReadTask
*task
);
63 static void redisSetReplyReaderError(redisReader
*r
, sds err
);
65 /* Default set of functions to build the reply. */
66 static redisReplyObjectFunctions defaultFunctions
= {
74 /* Create a reply object */
75 static redisReply
*createReplyObject(int type
) {
76 redisReply
*r
= malloc(sizeof(*r
));
83 /* Free a reply object */
84 void freeReplyObject(void *reply
) {
85 redisReply
*r
= reply
;
89 case REDIS_REPLY_INTEGER
:
90 break; /* Nothing to free */
91 case REDIS_REPLY_ARRAY
:
92 for (j
= 0; j
< r
->elements
; j
++)
93 if (r
->element
[j
]) freeReplyObject(r
->element
[j
]);
96 case REDIS_REPLY_ERROR
:
97 case REDIS_REPLY_STATUS
:
98 case REDIS_REPLY_STRING
:
105 static void *createStringObject(const redisReadTask
*task
, char *str
, size_t len
) {
106 redisReply
*r
= createReplyObject(task
->type
);
107 char *value
= malloc(len
+1);
108 if (!value
) redisOOM();
109 assert(task
->type
== REDIS_REPLY_ERROR
||
110 task
->type
== REDIS_REPLY_STATUS
||
111 task
->type
== REDIS_REPLY_STRING
);
113 /* Copy string value */
114 memcpy(value
,str
,len
);
120 redisReply
*parent
= task
->parent
->obj
;
121 assert(parent
->type
== REDIS_REPLY_ARRAY
);
122 parent
->element
[task
->idx
] = r
;
127 static void *createArrayObject(const redisReadTask
*task
, int elements
) {
128 redisReply
*r
= createReplyObject(REDIS_REPLY_ARRAY
);
129 r
->elements
= elements
;
130 if ((r
->element
= calloc(sizeof(redisReply
*),elements
)) == NULL
)
133 redisReply
*parent
= task
->parent
->obj
;
134 assert(parent
->type
== REDIS_REPLY_ARRAY
);
135 parent
->element
[task
->idx
] = r
;
140 static void *createIntegerObject(const redisReadTask
*task
, long long value
) {
141 redisReply
*r
= createReplyObject(REDIS_REPLY_INTEGER
);
144 redisReply
*parent
= task
->parent
->obj
;
145 assert(parent
->type
== REDIS_REPLY_ARRAY
);
146 parent
->element
[task
->idx
] = r
;
151 static void *createNilObject(const redisReadTask
*task
) {
152 redisReply
*r
= createReplyObject(REDIS_REPLY_NIL
);
154 redisReply
*parent
= task
->parent
->obj
;
155 assert(parent
->type
== REDIS_REPLY_ARRAY
);
156 parent
->element
[task
->idx
] = r
;
161 static char *readBytes(redisReader
*r
, unsigned int bytes
) {
163 if (r
->len
-r
->pos
>= bytes
) {
171 /* Find pointer to \r\n. */
172 static char *seekNewline(char *s
, size_t len
) {
176 /* Position should be < len-1 because the character at "pos" should be
177 * followed by a \n. Note that strchr cannot be used because it doesn't
178 * allow to search a limited length and the buffer that is being searched
179 * might not have a trailing NULL character. */
181 while(pos
< _len
&& s
[pos
] != '\r') pos
++;
182 if (s
[pos
] != '\r') {
186 if (s
[pos
+1] == '\n') {
190 /* Continue searching. */
198 /* Read a long long value starting at *s, under the assumption that it will be
199 * terminated by \r\n. Ambiguously returns -1 for unexpected input. */
200 static long long readLongLong(char *s
) {
208 } else if (*s
== '+') {
213 while ((c
= *(s
++)) != '\r') {
215 if (dec
>= 0 && dec
< 10) {
219 /* Should not happen... */
227 static char *readLine(redisReader
*r
, int *_len
) {
232 s
= seekNewline(p
,(r
->len
-r
->pos
));
234 len
= s
-(r
->buf
+r
->pos
);
235 r
->pos
+= len
+2; /* skip \r\n */
236 if (_len
) *_len
= len
;
242 static void moveToNextTask(redisReader
*r
) {
243 redisReadTask
*cur
, *prv
;
244 while (r
->ridx
>= 0) {
245 /* Return a.s.a.p. when the stack is now empty. */
251 cur
= &(r
->rstack
[r
->ridx
]);
252 prv
= &(r
->rstack
[r
->ridx
-1]);
253 assert(prv
->type
== REDIS_REPLY_ARRAY
);
254 if (cur
->idx
== prv
->elements
-1) {
257 /* Reset the type because the next item can be anything */
258 assert(cur
->idx
< prv
->elements
);
267 static int processLineItem(redisReader
*r
) {
268 redisReadTask
*cur
= &(r
->rstack
[r
->ridx
]);
273 if ((p
= readLine(r
,&len
)) != NULL
) {
275 if (cur
->type
== REDIS_REPLY_INTEGER
) {
276 obj
= r
->fn
->createInteger(cur
,readLongLong(p
));
278 obj
= r
->fn
->createString(cur
,p
,len
);
281 obj
= (void*)(size_t)(cur
->type
);
284 /* Set reply if this is the root object. */
285 if (r
->ridx
== 0) r
->reply
= obj
;
292 static int processBulkItem(redisReader
*r
) {
293 redisReadTask
*cur
= &(r
->rstack
[r
->ridx
]);
297 unsigned long bytelen
;
301 s
= seekNewline(p
,r
->len
-r
->pos
);
304 bytelen
= s
-(r
->buf
+r
->pos
)+2; /* include \r\n */
305 len
= readLongLong(p
);
308 /* The nil object can always be created. */
309 obj
= r
->fn
? r
->fn
->createNil(cur
) :
310 (void*)REDIS_REPLY_NIL
;
313 /* Only continue when the buffer contains the entire bulk item. */
314 bytelen
+= len
+2; /* include \r\n */
315 if (r
->pos
+bytelen
<= r
->len
) {
316 obj
= r
->fn
? r
->fn
->createString(cur
,s
+2,len
) :
317 (void*)REDIS_REPLY_STRING
;
322 /* Proceed when obj was created. */
326 /* Set reply if this is the root object. */
327 if (r
->ridx
== 0) r
->reply
= obj
;
335 static int processMultiBulkItem(redisReader
*r
) {
336 redisReadTask
*cur
= &(r
->rstack
[r
->ridx
]);
342 /* Set error for nested multi bulks with depth > 1 */
344 redisSetReplyReaderError(r
,sdscatprintf(sdsempty(),
345 "No support for nested multi bulk replies with depth > 1"));
349 if ((p
= readLine(r
,NULL
)) != NULL
) {
350 elements
= readLongLong(p
);
351 root
= (r
->ridx
== 0);
353 if (elements
== -1) {
354 obj
= r
->fn
? r
->fn
->createNil(cur
) :
355 (void*)REDIS_REPLY_NIL
;
358 obj
= r
->fn
? r
->fn
->createArray(cur
,elements
) :
359 (void*)REDIS_REPLY_ARRAY
;
361 /* Modify task stack when there are more than 0 elements. */
363 cur
->elements
= elements
;
366 r
->rstack
[r
->ridx
].type
= -1;
367 r
->rstack
[r
->ridx
].elements
= -1;
368 r
->rstack
[r
->ridx
].idx
= 0;
369 r
->rstack
[r
->ridx
].obj
= NULL
;
370 r
->rstack
[r
->ridx
].parent
= cur
;
371 r
->rstack
[r
->ridx
].privdata
= r
->privdata
;
377 /* Set reply if this is the root object. */
378 if (root
) r
->reply
= obj
;
384 static int processItem(redisReader
*r
) {
385 redisReadTask
*cur
= &(r
->rstack
[r
->ridx
]);
389 /* check if we need to read type */
391 if ((p
= readBytes(r
,1)) != NULL
) {
394 cur
->type
= REDIS_REPLY_ERROR
;
397 cur
->type
= REDIS_REPLY_STATUS
;
400 cur
->type
= REDIS_REPLY_INTEGER
;
403 cur
->type
= REDIS_REPLY_STRING
;
406 cur
->type
= REDIS_REPLY_ARRAY
;
409 byte
= sdscatrepr(sdsempty(),p
,1);
410 redisSetReplyReaderError(r
,sdscatprintf(sdsempty(),
411 "Protocol error, got %s as reply type byte", byte
));
416 /* could not consume 1 byte */
421 /* process typed item */
423 case REDIS_REPLY_ERROR
:
424 case REDIS_REPLY_STATUS
:
425 case REDIS_REPLY_INTEGER
:
426 return processLineItem(r
);
427 case REDIS_REPLY_STRING
:
428 return processBulkItem(r
);
429 case REDIS_REPLY_ARRAY
:
430 return processMultiBulkItem(r
);
437 void *redisReplyReaderCreate() {
438 redisReader
*r
= calloc(sizeof(redisReader
),1);
440 r
->fn
= &defaultFunctions
;
446 /* Set the function set to build the reply. Returns REDIS_OK when there
447 * is no temporary object and it can be set, REDIS_ERR otherwise. */
448 int redisReplyReaderSetReplyObjectFunctions(void *reader
, redisReplyObjectFunctions
*fn
) {
449 redisReader
*r
= reader
;
450 if (r
->reply
== NULL
) {
457 /* Set the private data field that is used in the read tasks. This argument can
458 * be used to curry arbitrary data to the custom reply object functions. */
459 int redisReplyReaderSetPrivdata(void *reader
, void *privdata
) {
460 redisReader
*r
= reader
;
461 if (r
->reply
== NULL
) {
462 r
->privdata
= privdata
;
468 /* External libraries wrapping hiredis might need access to the temporary
469 * variable while the reply is built up. When the reader contains an
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
;
477 void redisReplyReaderFree(void *reader
) {
478 redisReader
*r
= reader
;
479 if (r
->error
!= NULL
)
481 if (r
->reply
!= NULL
&& r
->fn
)
482 r
->fn
->freeObject(r
->reply
);
488 static void redisSetReplyReaderError(redisReader
*r
, sds err
) {
489 if (r
->reply
!= NULL
)
490 r
->fn
->freeObject(r
->reply
);
492 /* Clear remaining buffer when we see a protocol error. */
493 if (r
->buf
!= NULL
) {
502 char *redisReplyReaderGetError(void *reader
) {
503 redisReader
*r
= reader
;
507 void redisReplyReaderFeed(void *reader
, char *buf
, size_t len
) {
508 redisReader
*r
= reader
;
510 /* Copy the provided buffer. */
511 if (buf
!= NULL
&& len
>= 1) {
512 r
->buf
= sdscatlen(r
->buf
,buf
,len
);
513 r
->len
= sdslen(r
->buf
);
517 int redisReplyReaderGetReply(void *reader
, void **reply
) {
518 redisReader
*r
= reader
;
519 if (reply
!= NULL
) *reply
= NULL
;
521 /* When the buffer is empty, there will never be a reply. */
525 /* Set first item to process when the stack is empty. */
527 r
->rstack
[0].type
= -1;
528 r
->rstack
[0].elements
= -1;
529 r
->rstack
[0].idx
= -1;
530 r
->rstack
[0].obj
= NULL
;
531 r
->rstack
[0].parent
= NULL
;
532 r
->rstack
[0].privdata
= r
->privdata
;
536 /* Process items in reply. */
538 if (processItem(r
) < 0)
541 /* Discard the consumed part of the buffer. */
543 if (r
->pos
== r
->len
) {
544 /* sdsrange has a quirck on this edge case. */
548 r
->buf
= sdsrange(r
->buf
,r
->pos
,r
->len
);
551 r
->len
= sdslen(r
->buf
);
554 /* Emit a reply when there is one. */
556 void *aux
= r
->reply
;
559 /* Destroy the buffer when it is empty and is quite large. */
560 if (r
->len
== 0 && sdsavail(r
->buf
) > 16*1024) {
566 /* Check if there actually *is* a reply. */
567 if (r
->error
!= NULL
) {
570 if (reply
!= NULL
) *reply
= aux
;
576 /* Calculate the number of bytes needed to represent an integer as string. */
577 static int intlen(int i
) {
590 /* Helper function for redisvFormatCommand(). */
591 static void addArgument(sds a
, char ***argv
, int *argc
, int *totlen
) {
593 if ((*argv
= realloc(*argv
, sizeof(char*)*(*argc
))) == NULL
) redisOOM();
594 if (totlen
) *totlen
= *totlen
+1+intlen(sdslen(a
))+2+sdslen(a
)+2;
595 (*argv
)[(*argc
)-1] = a
;
598 int redisvFormatCommand(char **target
, const char *format
, va_list ap
) {
600 const char *arg
, *c
= format
;
601 char *cmd
= NULL
; /* final command */
602 int pos
; /* position in final command */
603 sds current
; /* current argument */
604 int interpolated
= 0; /* did we do interpolation on an argument? */
609 /* Abort if there is not target to set */
613 /* Build the command string accordingly to protocol */
614 current
= sdsempty();
616 if (*c
!= '%' || c
[1] == '\0') {
618 if (sdslen(current
) != 0) {
619 addArgument(current
, &argv
, &argc
, &totlen
);
620 current
= sdsempty();
624 current
= sdscatlen(current
,c
,1);
629 arg
= va_arg(ap
,char*);
632 current
= sdscatlen(current
,arg
,size
);
636 arg
= va_arg(ap
,char*);
637 size
= va_arg(ap
,size_t);
639 current
= sdscatlen(current
,arg
,size
);
643 current
= sdscat(current
,"%");
646 /* Try to detect printf format */
649 const char *_p
= c
+1;
654 if (*_p
!= '\0' && *_p
== '#') _p
++;
655 if (*_p
!= '\0' && *_p
== '0') _p
++;
656 if (*_p
!= '\0' && *_p
== '-') _p
++;
657 if (*_p
!= '\0' && *_p
== ' ') _p
++;
658 if (*_p
!= '\0' && *_p
== '+') _p
++;
661 while (*_p
!= '\0' && isdigit(*_p
)) _p
++;
666 while (*_p
!= '\0' && isdigit(*_p
)) _p
++;
671 if (*_p
== 'h' || *_p
== 'l') {
672 /* Allow a single repetition for these modifiers */
673 if (_p
[0] == _p
[1]) _p
++;
678 /* Conversion specifier */
679 if (*_p
!= '\0' && strchr("diouxXeEfFgGaA",*_p
) != NULL
) {
681 if (_l
< sizeof(_format
)-2) {
682 memcpy(_format
,c
,_l
);
685 current
= sdscatvprintf(current
,_format
,_cpy
);
689 /* Update current position (note: outer blocks
690 * increment c twice so compensate here) */
695 /* Consume and discard vararg */
704 /* Add the last argument if needed */
705 if (interpolated
|| sdslen(current
) != 0) {
706 addArgument(current
, &argv
, &argc
, &totlen
);
711 /* Add bytes needed to hold multi bulk count */
712 totlen
+= 1+intlen(argc
)+2;
714 /* Build the command at protocol level */
715 cmd
= malloc(totlen
+1);
716 if (!cmd
) redisOOM();
717 pos
= sprintf(cmd
,"*%d\r\n",argc
);
718 for (j
= 0; j
< argc
; j
++) {
719 pos
+= sprintf(cmd
+pos
,"$%zu\r\n",sdslen(argv
[j
]));
720 memcpy(cmd
+pos
,argv
[j
],sdslen(argv
[j
]));
721 pos
+= sdslen(argv
[j
]);
726 assert(pos
== totlen
);
733 /* Format a command according to the Redis protocol. This function
734 * takes a format similar to printf:
736 * %s represents a C null terminated string you want to interpolate
737 * %b represents a binary safe string
739 * When using %b you need to provide both the pointer to the string
740 * and the length in bytes. Examples:
742 * len = redisFormatCommand(target, "GET %s", mykey);
743 * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen);
745 int redisFormatCommand(char **target
, const char *format
, ...) {
749 len
= redisvFormatCommand(target
,format
,ap
);
754 /* Format a command according to the Redis protocol. This function takes the
755 * number of arguments, an array with arguments and an array with their
756 * lengths. If the latter is set to NULL, strlen will be used to compute the
759 int redisFormatCommandArgv(char **target
, int argc
, const char **argv
, const size_t *argvlen
) {
760 char *cmd
= NULL
; /* final command */
761 int pos
; /* position in final command */
765 /* Calculate number of bytes needed for the command */
766 totlen
= 1+intlen(argc
)+2;
767 for (j
= 0; j
< argc
; j
++) {
768 len
= argvlen
? argvlen
[j
] : strlen(argv
[j
]);
769 totlen
+= 1+intlen(len
)+2+len
+2;
772 /* Build the command at protocol level */
773 cmd
= malloc(totlen
+1);
774 if (!cmd
) redisOOM();
775 pos
= sprintf(cmd
,"*%d\r\n",argc
);
776 for (j
= 0; j
< argc
; j
++) {
777 len
= argvlen
? argvlen
[j
] : strlen(argv
[j
]);
778 pos
+= sprintf(cmd
+pos
,"$%zu\r\n",len
);
779 memcpy(cmd
+pos
,argv
[j
],len
);
784 assert(pos
== totlen
);
790 void __redisSetError(redisContext
*c
, int type
, const sds errstr
) {
792 if (errstr
!= NULL
) {
795 /* Only REDIS_ERR_IO may lack a description! */
796 assert(type
== REDIS_ERR_IO
);
797 c
->errstr
= sdsnew(strerror(errno
));
801 static redisContext
*redisContextInit() {
802 redisContext
*c
= calloc(sizeof(redisContext
),1);
805 c
->obuf
= sdsempty();
806 c
->fn
= &defaultFunctions
;
811 void redisFree(redisContext
*c
) {
812 /* Disconnect before free'ing if not yet disconnected. */
813 if (c
->flags
& REDIS_CONNECTED
)
815 if (c
->errstr
!= NULL
)
819 if (c
->reader
!= NULL
)
820 redisReplyReaderFree(c
->reader
);
824 /* Connect to a Redis instance. On error the field error in the returned
825 * context will be set to the return value of the error function.
826 * When no set of reply functions is given, the default set will be used. */
827 redisContext
*redisConnect(const char *ip
, int port
) {
828 redisContext
*c
= redisContextInit();
829 c
->flags
|= REDIS_BLOCK
;
830 redisContextConnectTcp(c
,ip
,port
);
834 redisContext
*redisConnectNonBlock(const char *ip
, int port
) {
835 redisContext
*c
= redisContextInit();
836 c
->flags
&= ~REDIS_BLOCK
;
837 redisContextConnectTcp(c
,ip
,port
);
841 redisContext
*redisConnectUnix(const char *path
) {
842 redisContext
*c
= redisContextInit();
843 c
->flags
|= REDIS_BLOCK
;
844 redisContextConnectUnix(c
,path
);
848 redisContext
*redisConnectUnixNonBlock(const char *path
) {
849 redisContext
*c
= redisContextInit();
850 c
->flags
&= ~REDIS_BLOCK
;
851 redisContextConnectUnix(c
,path
);
855 /* Set the replyObjectFunctions to use. Returns REDIS_ERR when the reader
856 * was already initialized and the function set could not be re-set.
857 * Return REDIS_OK when they could be set. */
858 int redisSetReplyObjectFunctions(redisContext
*c
, redisReplyObjectFunctions
*fn
) {
859 if (c
->reader
!= NULL
)
865 /* Helper function to lazily create a reply reader. */
866 static void __redisCreateReplyReader(redisContext
*c
) {
867 if (c
->reader
== NULL
) {
868 c
->reader
= redisReplyReaderCreate();
869 assert(redisReplyReaderSetReplyObjectFunctions(c
->reader
,c
->fn
) == REDIS_OK
);
873 /* Use this function to handle a read event on the descriptor. It will try
874 * and read some bytes from the socket and feed them to the reply parser.
876 * After this function is called, you may use redisContextReadReply to
877 * see if there is a reply available. */
878 int redisBufferRead(redisContext
*c
) {
880 int nread
= read(c
->fd
,buf
,sizeof(buf
));
882 if (errno
== EAGAIN
) {
883 /* Try again later */
885 __redisSetError(c
,REDIS_ERR_IO
,NULL
);
888 } else if (nread
== 0) {
889 __redisSetError(c
,REDIS_ERR_EOF
,
890 sdsnew("Server closed the connection"));
893 __redisCreateReplyReader(c
);
894 redisReplyReaderFeed(c
->reader
,buf
,nread
);
899 /* Write the output buffer to the socket.
901 * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
902 * succesfully written to the socket. When the buffer is empty after the
903 * write operation, "wdone" is set to 1 (if given).
905 * Returns REDIS_ERR if an error occured trying to write and sets
906 * c->error to hold the appropriate error string.
908 int redisBufferWrite(redisContext
*c
, int *done
) {
910 if (sdslen(c
->obuf
) > 0) {
911 nwritten
= write(c
->fd
,c
->obuf
,sdslen(c
->obuf
));
912 if (nwritten
== -1) {
913 if (errno
== EAGAIN
) {
914 /* Try again later */
916 __redisSetError(c
,REDIS_ERR_IO
,NULL
);
919 } else if (nwritten
> 0) {
920 if (nwritten
== (signed)sdslen(c
->obuf
)) {
922 c
->obuf
= sdsempty();
924 c
->obuf
= sdsrange(c
->obuf
,nwritten
,-1);
928 if (done
!= NULL
) *done
= (sdslen(c
->obuf
) == 0);
932 /* Internal helper function to try and get a reply from the reader,
933 * or set an error in the context otherwise. */
934 int redisGetReplyFromReader(redisContext
*c
, void **reply
) {
935 __redisCreateReplyReader(c
);
936 if (redisReplyReaderGetReply(c
->reader
,reply
) == REDIS_ERR
) {
937 __redisSetError(c
,REDIS_ERR_PROTOCOL
,
938 sdsnew(((redisReader
*)c
->reader
)->error
));
944 int redisGetReply(redisContext
*c
, void **reply
) {
948 /* Try to read pending replies */
949 if (redisGetReplyFromReader(c
,&aux
) == REDIS_ERR
)
952 /* For the blocking context, flush output buffer and read reply */
953 if (aux
== NULL
&& c
->flags
& REDIS_BLOCK
) {
954 /* Write until done */
956 if (redisBufferWrite(c
,&wdone
) == REDIS_ERR
)
960 /* Read until there is a reply */
962 if (redisBufferRead(c
) == REDIS_ERR
)
964 if (redisGetReplyFromReader(c
,&aux
) == REDIS_ERR
)
966 } while (aux
== NULL
);
969 /* Set reply object */
970 if (reply
!= NULL
) *reply
= aux
;
975 /* Helper function for the redisAppendCommand* family of functions.
977 * Write a formatted command to the output buffer. When this family
978 * is used, you need to call redisGetReply yourself to retrieve
979 * the reply (or replies in pub/sub).
981 void __redisAppendCommand(redisContext
*c
, char *cmd
, size_t len
) {
982 c
->obuf
= sdscatlen(c
->obuf
,cmd
,len
);
985 void redisvAppendCommand(redisContext
*c
, const char *format
, va_list ap
) {
988 len
= redisvFormatCommand(&cmd
,format
,ap
);
989 __redisAppendCommand(c
,cmd
,len
);
993 void redisAppendCommand(redisContext
*c
, const char *format
, ...) {
996 redisvAppendCommand(c
,format
,ap
);
1000 void redisAppendCommandArgv(redisContext
*c
, int argc
, const char **argv
, const size_t *argvlen
) {
1003 len
= redisFormatCommandArgv(&cmd
,argc
,argv
,argvlen
);
1004 __redisAppendCommand(c
,cmd
,len
);
1008 /* Helper function for the redisCommand* family of functions.
1010 * Write a formatted command to the output buffer. If the given context is
1011 * blocking, immediately read the reply into the "reply" pointer. When the
1012 * context is non-blocking, the "reply" pointer will not be used and the
1013 * command is simply appended to the write buffer.
1015 * Returns the reply when a reply was succesfully retrieved. Returns NULL
1016 * otherwise. When NULL is returned in a blocking context, the error field
1017 * in the context will be set.
1019 static void *__redisCommand(redisContext
*c
, char *cmd
, size_t len
) {
1021 __redisAppendCommand(c
,cmd
,len
);
1023 if (c
->flags
& REDIS_BLOCK
) {
1024 if (redisGetReply(c
,&aux
) == REDIS_OK
)
1031 void *redisvCommand(redisContext
*c
, const char *format
, va_list ap
) {
1035 len
= redisvFormatCommand(&cmd
,format
,ap
);
1036 reply
= __redisCommand(c
,cmd
,len
);
1041 void *redisCommand(redisContext
*c
, const char *format
, ...) {
1044 va_start(ap
,format
);
1045 reply
= redisvCommand(c
,format
,ap
);
1050 void *redisCommandArgv(redisContext
*c
, int argc
, const char **argv
, const size_t *argvlen
) {
1054 len
= redisFormatCommandArgv(&cmd
,argc
,argv
,argvlen
);
1055 reply
= __redisCommand(c
,cmd
,len
);