Format a command using an argument vector
This commit is contained in:
parent
e95c9d4c5b
commit
a3a405bcba
36
hiredis.c
36
hiredis.c
@ -578,6 +578,42 @@ int redisFormatCommand(char **target, const char *format, ...) {
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Format a command according to the Redis protocol. This function takes the
|
||||
* number of arguments, an array with arguments and an array with their
|
||||
* lengths. If the latter is set to NULL, strlen will be used to compute the
|
||||
* argument lengths.
|
||||
*/
|
||||
int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen) {
|
||||
char *cmd = NULL; /* final command */
|
||||
int pos; /* position in final command */
|
||||
size_t len;
|
||||
int totlen, j;
|
||||
|
||||
/* Calculate number of bytes needed for the command */
|
||||
totlen = 1+intlen(argc)+2;
|
||||
for (j = 0; j < argc; j++) {
|
||||
len = argvlen ? argvlen[j] : strlen(argv[j]);
|
||||
totlen += 1+intlen(len)+2+len+2;
|
||||
}
|
||||
|
||||
/* Build the command at protocol level */
|
||||
cmd = malloc(totlen+1);
|
||||
if (!cmd) redisOOM();
|
||||
pos = sprintf(cmd,"*%d\r\n",argc);
|
||||
for (j = 0; j < argc; j++) {
|
||||
len = argvlen ? argvlen[j] : strlen(argv[j]);
|
||||
pos += sprintf(cmd+pos,"$%zu\r\n",len);
|
||||
memcpy(cmd+pos,argv[j],len);
|
||||
pos += len;
|
||||
cmd[pos++] = '\r';
|
||||
cmd[pos++] = '\n';
|
||||
}
|
||||
assert(pos == totlen);
|
||||
cmd[totlen] = '\0';
|
||||
*target = cmd;
|
||||
return totlen;
|
||||
}
|
||||
|
||||
static int redisContextConnect(redisContext *c, const char *ip, int port) {
|
||||
char err[ANET_ERR_LEN];
|
||||
if (c->flags & REDIS_BLOCK) {
|
||||
|
@ -125,6 +125,7 @@ int redisReplyReaderGetReply(void *reader, void **reply);
|
||||
/* Functions to format a command according to the protocol. */
|
||||
int redisvFormatCommand(char **target, const char *format, va_list ap);
|
||||
int redisFormatCommand(char **target, const char *format, ...);
|
||||
int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen);
|
||||
|
||||
redisContext *redisConnect(const char *ip, int port, redisReplyObjectFunctions *fn);
|
||||
redisContext *redisConnectNonBlock(const char *ip, int port, redisReplyObjectFunctions *fn);
|
||||
|
43
test.c
43
test.c
@ -28,6 +28,48 @@ static void __connect(redisContext **target) {
|
||||
}
|
||||
}
|
||||
|
||||
static void test_format_commands() {
|
||||
char *cmd;
|
||||
int len;
|
||||
|
||||
test("Format command without interpolation: ");
|
||||
len = redisFormatCommand(&cmd,"SET foo bar");
|
||||
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 &&
|
||||
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
|
||||
free(cmd);
|
||||
|
||||
test("Format command with %%s string interpolation: ");
|
||||
len = redisFormatCommand(&cmd,"SET %s %s","foo","bar");
|
||||
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 &&
|
||||
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
|
||||
free(cmd);
|
||||
|
||||
test("Format command with %%b string interpolation: ");
|
||||
len = redisFormatCommand(&cmd,"SET %b %b","foo",3,"b\0r",3);
|
||||
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nb\0r\r\n",len) == 0 &&
|
||||
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
|
||||
free(cmd);
|
||||
|
||||
const char *argv[3];
|
||||
argv[0] = "SET";
|
||||
argv[1] = "foo";
|
||||
argv[2] = "bar";
|
||||
size_t lens[3] = { 3, 3, 3 };
|
||||
int argc = 3;
|
||||
|
||||
test("Format command by passing argc/argv without lengths: ");
|
||||
len = redisFormatCommandArgv(&cmd,argc,argv,NULL);
|
||||
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 &&
|
||||
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
|
||||
free(cmd);
|
||||
|
||||
test("Format command by passing argc/argv with lengths: ");
|
||||
len = redisFormatCommandArgv(&cmd,argc,argv,lens);
|
||||
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 &&
|
||||
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
static void test_blocking_connection() {
|
||||
redisContext *c;
|
||||
redisReply *reply;
|
||||
@ -294,6 +336,7 @@ static void test_nonblocking_connection() {
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
test_format_commands();
|
||||
test_blocking_connection();
|
||||
test_reply_reader();
|
||||
test_nonblocking_connection();
|
||||
|
Loading…
Reference in New Issue
Block a user