想要直接用hiredis调用lua脚本,研究了好久发现hiredis源码好像不支持调用eval,因为hiredis中是用空格来分割各个参数的,但是lua的return和结果之间一定会有空格。
改了一下hiredis的源码,int redisvFormatCommand(char **target, const char *format, va_list ap) 这个接口,
int redisvFormatCommand(char **target, const char *format, va_list ap) {
const char *c = format;
char *cmd = NULL; /* final command */
int pos; /* position in final command */
sds curarg, newarg; /* current argument */
int touched = 0; /* was the current argument touched? */
char **curargv = NULL, **newargv = NULL;
int argc = 0;
int totlen = 0;
int j;
BOOL quote = 0; //用来判断是否是lua脚本
/* Abort if there is not target to set */
if (target == NULL)
return -1;
/* Build the command string accordingly to protocol */
curarg = sdsempty();
if (curarg == NULL)
return -1;
while(*c != '\0') {
if (*c != '%' || c[1] == '\0') {
if (*c == ' ') {
if (quote)
{
newarg = sdscatlen(curarg, c, 1);
if (newarg == NULL) goto err;
curarg = newarg;
touched = 1;
}
else if (touched) {
newargv = realloc(curargv,sizeof(char*)*(argc+1));
if (newargv == NULL) goto err;
curargv = newargv;
curargv[argc++] = curarg;
totlen += (int)bulklen(sdslen(curarg));
/* curarg is put in argv so it can be overwritten. */
curarg = sdsempty();
if (curarg == NULL) goto err;
touched = 0;
}
} else {
touched = 1;
if (*c == '"')
{
if (!quote)
{
quote = 1;
}
else
{
quote = 0;
}
}
else
{
newarg = sdscatlen(curarg, c, 1);
if (newarg == NULL) goto err;
curarg = newarg;
}
}
} else {
char *arg;
size_t size;
/* Set newarg so it can be checked even if it is not touched. */
newarg = curarg;
switch(c[1]) {
case 's':
arg = va_arg(ap,char*);
size = strlen(arg);
if (size > 0)
newarg = sdscatlen(curarg,arg,size);
break;
case 'b':
arg = va_arg(ap,char*);
size = va_arg(ap,size_t);
if (size > 0)
newarg = sdscatlen(curarg,arg,size);
break;
case '%':
newarg = sdscat(curarg,"%");
break;
default:
/* Try to detect printf format */
{
static const char intfmts[] = "diouxX";
char _format[16];
const char *_p = c+1;
size_t _l = 0;
va_list _cpy;
/* Flags */
if (*_p != '\0' && *_p == '#') _p++;
if (*_p != '\0' && *_p == '0') _p++;
if (*_p != '\0' && *_p == '-') _p++;
if (*_p != '\0' && *_p == ' ') _p++;
if (*_p != '\0' && *_p == '+') _p++;
/* Field width */
while (*_p != '\0' && isdigit(*_p)) _p++;
/* Precision */
if (*_p == '.') {
_p++;
while (*_p != '\0' && isdigit(*_p)) _p++;
}
/* Copy va_list before consuming with va_arg */
va_copy(_cpy,ap);
/* Integer conversion (without modifiers) */
if (strchr(intfmts,*_p) != NULL) {
va_arg(ap,int);
goto fmt_valid;
}
/* Double conversion (without modifiers) */
if (strchr("eEfFgGaA",*_p) != NULL) {
va_arg(ap,double);
goto fmt_valid;
}
/* Size: char */
if (_p[0] == 'h' && _p[1] == 'h') {
_p += 2;
if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
va_arg(ap,int); /* char gets promoted to int */
goto fmt_valid;
}
goto fmt_invalid;
}
/* Size: short */
if (_p[0] == 'h') {
_p += 1;
if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
va_arg(ap,int); /* short gets promoted to int */
goto fmt_valid;
}
goto fmt_invalid;
}
/* Size: long long */
if (_p[0] == 'l' && _p[1] == 'l') {
_p += 2;
if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
va_arg(ap,long long);
goto fmt_valid;
}
goto fmt_invalid;
}
/* Size: long */
if (_p[0] == 'l') {
_p += 1;
if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
va_arg(ap,long);
goto fmt_valid;
}
goto fmt_invalid;
}
fmt_invalid:
va_end(_cpy);
goto err;
fmt_valid:
_l = (_p+1)-c;
if (_l < sizeof(_format)-2) {
memcpy(_format,c,_l);
_format[_l] = '\0';
newarg = sdscatvprintf(curarg,_format,_cpy);
/* Update current position (note: outer blocks
* increment c twice so compensate here) */
c = _p-1;
}
va_end(_cpy);
break;
}
}
if (newarg == NULL) goto err;
curarg = newarg;
touched = 1;
c++;
}
c++;
}
/* Add the last argument if needed */
if (touched) {
newargv = realloc(curargv,sizeof(char*)*(argc+1));
if (newargv == NULL) goto err;
curargv = newargv;
curargv[argc++] = curarg;
totlen += (int)bulklen(sdslen(curarg));
} else {
sdsfree(curarg);
}
/* Clear curarg because it was put in curargv or was free'd. */
curarg = NULL;
/* Add bytes needed to hold multi bulk count */
totlen += 1+intlen(argc)+2;
/* Build the command at protocol level */
cmd = (char *)malloc(totlen+1);
if (cmd == NULL) goto err;
pos = sprintf(cmd,"*%d\r\n",argc);
for (j = 0; j < argc; j++) {
#ifdef _WIN32
pos += sprintf(cmd+pos,"$%llu\r\n",(unsigned long long)sdslen(curargv[j]));
#else
pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j]));
#endif
memcpy(cmd+pos,curargv[j],sdslen(curargv[j]));
pos += (int)sdslen(curargv[j]);
sdsfree(curargv[j]);
cmd[pos++] = '\r';
cmd[pos++] = '\n';
}
assert(pos == totlen);
cmd[pos] = '\0';
free(curargv);
*target = cmd;
return totlen;
err:
while(argc--)
sdsfree(curargv[argc]);
free(curargv);
if (curarg != NULL)
sdsfree(curarg);
/* No need to check cmd since it is the last statement that can fail,
* but do it anyway to be as defensive as possible. */
if (cmd != NULL)
free(cmd);
return -1;
}
redisAppendCommand(c, "EVAL \"redis.call('SET', KEYS[1], ARGV[1]) local result = redis.call('get',KEYS[1]) return result\" 1 foo1 bar1");
if (redisGetReply(c, (void**)&r) != REDIS_OK)
return;
redisAppendCommand(c, "script load \"redis.call('SET', KEYS[1], ARGV[1]) local result = redis.call('get', KEYS[1]) return result\"");
if (redisGetReply(c, (void**)&r) != REDIS_OK)
return;
获得 SHA1 校验结果,下次执行只需要执行:evalsha 53d14bf87fe54b95654989afb59c43b1c70d2afb 1 foo1 bar1即可。
redisAppendCommand(c, "script load \"redis.call('SET', KEYS[1], ARGV[1]) local result = redis.call('get', KEYS[1]) return result\"");
if (redisGetReply(c, (void**)&r) != REDIS_OK)
return;
printf("------%s\n", r->str);
//freeReplyObject(r);
std::string tmpstr = "evalsha ";
tmpstr += r->str;
tmpstr += " 1 foo3 bar3";
redisAppendCommand(c, tmpstr.c_str());
if (redisGetReply(c, (void**)&r) != REDIS_OK)
return;
printf("------%s\n", r->str);
freeReplyObject(r);