Expect a valid multi-bulk command in the debugging client query buffer. * On success the command is parsed and returned as an array of SDS strings, * otherwise NULL is returned and there is to read more buffer. */
| 2135 | * On success the command is parsed and returned as an array of SDS strings, |
| 2136 | * otherwise NULL is returned and there is to read more buffer. */ |
| 2137 | sds *ldbReplParseCommand(int *argcp, char** err) { |
| 2138 | static sds protocol_error = sdsnew("protocol error"); |
| 2139 | sds *argv = NULL; |
| 2140 | int argc = 0; |
| 2141 | char *plen = NULL; |
| 2142 | if (sdslen(ldb.cbuf) == 0) return NULL; |
| 2143 | |
| 2144 | /* Working on a copy is simpler in this case. We can modify it freely |
| 2145 | * for the sake of simpler parsing. */ |
| 2146 | sds copy = sdsdup(ldb.cbuf); |
| 2147 | char *p = copy; |
| 2148 | |
| 2149 | /* This Redis protocol parser is a joke... just the simplest thing that |
| 2150 | * works in this context. It is also very forgiving regarding broken |
| 2151 | * protocol. */ |
| 2152 | |
| 2153 | /* Seek and parse *<count>\r\n. */ |
| 2154 | p = strchr(p,'*'); if (!p) goto protoerr; |
| 2155 | plen = p+1; /* Multi bulk len pointer. */ |
| 2156 | p = strstr(p,"\r\n"); if (!p) goto keep_reading; |
| 2157 | *p = '\0'; p += 2; |
| 2158 | *argcp = atoi(plen); |
| 2159 | if (*argcp <= 0 || *argcp > 1024) goto protoerr; |
| 2160 | |
| 2161 | /* Parse each argument. */ |
| 2162 | argv = (sds*)zmalloc(sizeof(sds)*(*argcp), MALLOC_LOCAL); |
| 2163 | argc = 0; |
| 2164 | while(argc < *argcp) { |
| 2165 | /* reached the end but there should be more data to read */ |
| 2166 | if (*p == '\0') goto keep_reading; |
| 2167 | |
| 2168 | if (*p != '$') goto protoerr; |
| 2169 | plen = p+1; /* Bulk string len pointer. */ |
| 2170 | p = strstr(p,"\r\n"); if (!p) goto keep_reading; |
| 2171 | *p = '\0'; p += 2; |
| 2172 | int slen = atoi(plen); /* Length of this arg. */ |
| 2173 | if (slen <= 0 || slen > 1024) goto protoerr; |
| 2174 | if ((size_t)(p + slen + 2 - copy) > sdslen(copy) ) goto keep_reading; |
| 2175 | argv[argc++] = sdsnewlen(p,slen); |
| 2176 | p += slen; /* Skip the already parsed argument. */ |
| 2177 | if (p[0] != '\r' || p[1] != '\n') goto protoerr; |
| 2178 | p += 2; /* Skip \r\n. */ |
| 2179 | } |
| 2180 | sdsfree(copy); |
| 2181 | return argv; |
| 2182 | |
| 2183 | protoerr: |
| 2184 | *err = protocol_error; |
| 2185 | keep_reading: |
| 2186 | sdsfreesplitres(argv,argc); |
| 2187 | sdsfree(copy); |
| 2188 | return NULL; |
| 2189 | } |
| 2190 | |
| 2191 | /* Log the specified line in the Lua debugger output. */ |
| 2192 | void ldbLogSourceLine(int lnum) { |