]> git.saurik.com Git - redis.git/blobdiff - deps/hiredis/hiredis.c
quick and dirty fix for hiredis bug creating problem with the new redis-cli connect...
[redis.git] / deps / hiredis / hiredis.c
index 3c8736dc5a6502205fb755c40ea6dae52d3f7606..898b4d6afa950184bc5bf8f1e05182e318313364 100644 (file)
@@ -162,11 +162,29 @@ static char *readBytes(redisReader *r, unsigned int bytes) {
     return NULL;
 }
 
+static char *seekNewline(char *s) {
+    /* Find pointer to \r\n without strstr */
+    while (s != NULL) {
+        s = strchr(s,'\r');
+        if (s != NULL) {
+            if (s[1] == '\n')
+                break;
+            else
+                s++;
+        } else {
+            break;
+        }
+    }
+    return s;
+}
+
 static char *readLine(redisReader *r, int *_len) {
-    char *p, *s = strstr(r->buf+r->pos,"\r\n");
+    char *p, *s;
     int len;
+
+    p = r->buf+r->pos;
+    s = seekNewline(p);
     if (s != NULL) {
-        p = r->buf+r->pos;
         len = s-(r->buf+r->pos);
         r->pos += len+2; /* skip \r\n */
         if (_len) *_len = len;
@@ -177,26 +195,26 @@ static char *readLine(redisReader *r, int *_len) {
 
 static void moveToNextTask(redisReader *r) {
     redisReadTask *cur, *prv;
-    assert(r->ridx >= 0);
-
-    /* Return a.s.a.p. when the stack is now empty. */
-    if (r->ridx == 0) {
-        r->ridx--;
-        return;
-    }
+    while (r->ridx >= 0) {
+        /* Return a.s.a.p. when the stack is now empty. */
+        if (r->ridx == 0) {
+            r->ridx--;
+            return;
+        }
 
-    cur = &(r->rstack[r->ridx]);
-    prv = &(r->rstack[r->ridx-1]);
-    assert(prv->type == REDIS_REPLY_ARRAY);
-    if (cur->idx == prv->elements-1) {
-        r->ridx--;
-        moveToNextTask(r);
-    } else {
-        /* Reset the type because the next item can be anything */
-        assert(cur->idx < prv->elements);
-        cur->type = -1;
-        cur->elements = -1;
-        cur->idx++;
+        cur = &(r->rstack[r->ridx]);
+        prv = &(r->rstack[r->ridx-1]);
+        assert(prv->type == REDIS_REPLY_ARRAY);
+        if (cur->idx == prv->elements-1) {
+            r->ridx--;
+        } else {
+            /* Reset the type because the next item can be anything */
+            assert(cur->idx < prv->elements);
+            cur->type = -1;
+            cur->elements = -1;
+            cur->idx++;
+            return;
+        }
     }
 }
 
@@ -207,10 +225,14 @@ static int processLineItem(redisReader *r) {
     int len;
 
     if ((p = readLine(r,&len)) != NULL) {
-        if (cur->type == REDIS_REPLY_INTEGER) {
-            obj = r->fn->createInteger(cur,strtoll(p,NULL,10));
+        if (r->fn) {
+            if (cur->type == REDIS_REPLY_INTEGER) {
+                obj = r->fn->createInteger(cur,strtoll(p,NULL,10));
+            } else {
+                obj = r->fn->createString(cur,p,len);
+            }
         } else {
-            obj = r->fn->createString(cur,p,len);
+            obj = (void*)(size_t)(cur->type);
         }
 
         /* If there is no root yet, register this object as root. */
@@ -230,7 +252,7 @@ static int processBulkItem(redisReader *r) {
     unsigned long bytelen;
 
     p = r->buf+r->pos;
-    s = strstr(p,"\r\n");
+    s = seekNewline(p);
     if (s != NULL) {
         p = r->buf+r->pos;
         bytelen = s-(r->buf+r->pos)+2; /* include \r\n */
@@ -238,12 +260,14 @@ static int processBulkItem(redisReader *r) {
 
         if (len < 0) {
             /* The nil object can always be created. */
-            obj = r->fn->createNil(cur);
+            obj = r->fn ? r->fn->createNil(cur) :
+                (void*)REDIS_REPLY_NIL;
         } else {
             /* Only continue when the buffer contains the entire bulk item. */
             bytelen += len+2; /* include \r\n */
             if (r->pos+bytelen <= sdslen(r->buf)) {
-                obj = r->fn->createString(cur,s+2,len);
+                obj = r->fn ? r->fn->createString(cur,s+2,len) :
+                    (void*)REDIS_REPLY_STRING;
             }
         }
 
@@ -268,10 +292,12 @@ static int processMultiBulkItem(redisReader *r) {
     if ((p = readLine(r,NULL)) != NULL) {
         elements = strtol(p,NULL,10);
         if (elements == -1) {
-            obj = r->fn->createNil(cur);
+            obj = r->fn ? r->fn->createNil(cur) :
+                (void*)REDIS_REPLY_NIL;
             moveToNextTask(r);
         } else {
-            obj = r->fn->createArray(cur,elements);
+            obj = r->fn ? r->fn->createArray(cur,elements) :
+                (void*)REDIS_REPLY_ARRAY;
 
             /* Modify task stack when there are more than 0 elements. */
             if (elements > 0) {
@@ -348,15 +374,26 @@ static int processItem(redisReader *r) {
     }
 }
 
-void *redisReplyReaderCreate(redisReplyObjectFunctions *fn) {
+void *redisReplyReaderCreate() {
     redisReader *r = calloc(sizeof(redisReader),1);
     r->error = NULL;
-    r->fn = fn == NULL ? &defaultFunctions : fn;
+    r->fn = &defaultFunctions;
     r->buf = sdsempty();
     r->ridx = -1;
     return r;
 }
 
+/* Set the function set to build the reply. Returns REDIS_OK when there
+ * is no temporary object and it can be set, REDIS_ERR otherwise. */
+int redisReplyReaderSetReplyObjectFunctions(void *reader, redisReplyObjectFunctions *fn) {
+    redisReader *r = reader;
+    if (r->reply == NULL) {
+        r->fn = fn;
+        return REDIS_OK;
+    }
+    return REDIS_ERR;
+}
+
 /* External libraries wrapping hiredis might need access to the temporary
  * variable while the reply is built up. When the reader contains an
  * object in between receiving some bytes to parse, this object might
@@ -370,7 +407,7 @@ void redisReplyReaderFree(void *reader) {
     redisReader *r = reader;
     if (r->error != NULL)
         sdsfree(r->error);
-    if (r->reply != NULL)
+    if (r->reply != NULL && r->fn)
         r->fn->freeObject(r->reply);
     if (r->buf != NULL)
         sdsfree(r->buf);
@@ -396,7 +433,7 @@ char *redisReplyReaderGetError(void *reader) {
     return r->error;
 }
 
-void redisReplyReaderFeed(void *reader, char *buf, int len) {
+void redisReplyReaderFeed(void *reader, char *buf, size_t len) {
     redisReader *r = reader;
 
     /* Copy the provided buffer. */
@@ -627,6 +664,7 @@ void __redisSetError(redisContext *c, int type, const sds errstr) {
 
 static redisContext *redisContextInit() {
     redisContext *c = calloc(sizeof(redisContext),1);
+    c->fd = -1; /* quick fix for a bug that should be addressed differently */
     c->err = 0;
     c->errstr = NULL;
     c->obuf = sdsempty();
@@ -695,8 +733,10 @@ int redisSetReplyObjectFunctions(redisContext *c, redisReplyObjectFunctions *fn)
 
 /* Helper function to lazily create a reply reader. */
 static void __redisCreateReplyReader(redisContext *c) {
-    if (c->reader == NULL)
-        c->reader = redisReplyReaderCreate(c->fn);
+    if (c->reader == NULL) {
+        c->reader = redisReplyReaderCreate();
+        assert(redisReplyReaderSetReplyObjectFunctions(c->reader,c->fn) == REDIS_OK);
+    }
 }
 
 /* Use this function to handle a read event on the descriptor. It will try