sds *ldbReplParseCommand(int *argcp, char** err) {
    static char* protocol_error = "protocol error";
    sds *argv = NULL;
    int argc = 0;
    if (sdslen(ldb.cbuf) == 0) return NULL;

    /* Working on a copy is simpler in this case. We can modify it freely
     * for the sake of simpler parsing. */
    sds copy = sdsdup(ldb.cbuf);
    char *p = copy;

    /* This Redis protocol parser is a joke... just the simplest thing that
     * works in this context. It is also very forgiving regarding broken
     * protocol. */

    /* Seek and parse *<count>\r\n. */
    p = strchr(p,'*'); if (!p) goto protoerr;
    char *plen = p+1; /* Multi bulk len pointer. */
    p = strstr(p,"\r\n"); if (!p) goto keep_reading;
    *p = '\0'; p += 2;
    *argcp = atoi(plen);
    if (*argcp <= 0 || *argcp > 1024) goto protoerr;

    /* Parse each argument. */
    argv = zmalloc(sizeof(sds)*(*argcp));
    argc = 0;
    while(argc < *argcp) {
        // reached the end but there should be more data to read
        if (*p == '\0') goto keep_reading;

        if (*p != '$') goto protoerr;
        plen = p+1; /* Bulk string len pointer. */
        p = strstr(p,"\r\n"); if (!p) goto keep_reading;
        *p = '\0'; p += 2;
        int slen = atoi(plen); /* Length of this arg. */
        if (slen <= 0 || slen > 1024) goto protoerr;
        if ((size_t)(p + slen + 2 - copy) > sdslen(copy) ) goto keep_reading;
        argv[argc++] = sdsnewlen(p,slen);
        p += slen; /* Skip the already parsed argument. */
        if (p[0] != '\r' || p[1] != '\n') goto protoerr;
        p += 2; /* Skip \r\n. */
    }
    sdsfree(copy);
    return argv;

protoerr:
    *err = protocol_error;
keep_reading:
    sdsfreesplitres(argv,argc);
    sdsfree(copy);
    return NULL;
}
sds *ldbReplParseCommand(int *argcp, char** err) {
    static char* protocol_error = "protocol error";
    sds *argv = NULL;
    int argc = 0;
    if (sdslen(ldb.cbuf) == 0) return NULL;

     
    sds copy = sdsdup(ldb.cbuf);
    char *p = copy;

     

     
    p = strchr(p,'*'); if (!p) goto protoerr;
    char *plen = p+1;  
    p = strstr(p,"\r\n"); if (!p) goto keep_reading;
    *p = '\0'; p += 2;
    *argcp = atoi(plen);
    if (*argcp <= 0 || *argcp > 1024) goto protoerr;

     
    argv = zmalloc(sizeof(sds)*(*argcp));
    argc = 0;
    while(argc < *argcp) {
         
        if (*p == '\0') goto keep_reading;

        if (*p != '$') goto protoerr;
        plen = p+1;  
        p = strstr(p,"\r\n"); if (!p) goto keep_reading;
        *p = '\0'; p += 2;
        int slen = atoi(plen);  
        if (slen <= 0 || slen > 1024) goto protoerr;
        if ((size_t)(p + slen + 2 - copy) > sdslen(copy) ) goto keep_reading;
        argv[argc++] = sdsnewlen(p,slen);
        p += slen;  
        if (p[0] != '\r' || p[1] != '\n') goto protoerr;
        p += 2;  
    }
    sdsfree(copy);
    return argv;

protoerr:
    *err = protocol_error;
keep_reading:
    sdsfreesplitres(argv,argc);
    sdsfree(copy);
    return NULL;
}