diff --git a/src/redis-cli.c b/src/redis-cli.c index 84a9c548..fccaaea6 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -525,7 +525,7 @@ sds sdsCatColorizedLdbReply(sds o, char *s, size_t len) { if (strstr(s,"")) color = "green"; if (strstr(s,"")) color = "cyan"; if (strstr(s,"")) color = "red"; - if (strstr(s,"")) color = "magenta"; + if (strstr(s,"") || strstr(s,"")) color = "magenta"; if (len > 4 && isdigit(s[3])) { if (s[1] == '>') color = "yellow"; /* Current line. */ else if (s[2] == '#') color = "bold"; /* Break point. */ diff --git a/src/scripting.c b/src/scripting.c index 3fc0e1ec..f64bc4e6 100644 --- a/src/scripting.c +++ b/src/scripting.c @@ -1728,48 +1728,99 @@ void ldbList(int around, int context) { } } -/* Produce a debugger log entry representing the value of the Lua object - * currently on the top of the stack. As a side effect the element is - * popped. */ -void ldbLogStackValue(lua_State *lua, char *prefix) { - int t = lua_type(lua,-1); - sds s = sdsnew(prefix); +/* Append an human readable representation of the Lua value at position 'idx' + * on the stack of the 'lua' state, to the SDS string passed as argument. + * The new SDS string with the represented value attached is returned. + * Used in order to implement ldbLogStackValue(). + * + * The element is not automatically removed from the stack, nor it is + * converted to a different type. */ +sds ldbCatStackValue(sds s, lua_State *lua, int idx) { + int t = lua_type(lua,idx); switch(t) { case LUA_TSTRING: - s = sdscat(s,lua_tostring(lua,-1)); + { + size_t strl; + char *strp = (char*)lua_tolstring(lua,idx,&strl); + s = sdscatrepr(s,strp,strl); + } break; case LUA_TBOOLEAN: - s = sdscat(s,lua_toboolean(lua,-1) ? "true" : "false"); + s = sdscat(s,lua_toboolean(lua,idx) ? "true" : "false"); break; case LUA_TNUMBER: - s = sdscatprintf(s,"%g",(double)lua_tonumber(lua,-1)); + s = sdscatprintf(s,"%g",(double)lua_tonumber(lua,idx)); break; case LUA_TNIL: - s = sdscat(s,"nil"); + s = sdscatlen(s,"nil",3); break; case LUA_TTABLE: + { + int expected_index = 1; /* First index we expect in an array. */ + int is_array = 1; /* Will be set to null if check fails. */ + /* Note: we create two representations at the same time, one + * assuming the table is an array, one assuming it is not. At the + * end we know what is true and select the right one. */ + sds repr1 = sdsempty(); + sds repr2 = sdsempty(); + lua_pushnil(lua); /* The first key to start the iteration is nil. */ + while (lua_next(lua,idx-1)) { + /* Test if so far the table looks like an array. */ + if (is_array && + (lua_type(lua,-2) != LUA_TNUMBER || + lua_tonumber(lua,-2) != expected_index)) is_array = 0; + /* Stack now: table, key, value */ + /* Array repr. */ + repr1 = ldbCatStackValue(repr1,lua,-1); + repr1 = sdscatlen(repr1,"; ",2); + /* Full repr. */ + repr2 = ldbCatStackValue(repr2,lua,-2); + repr2 = sdscatlen(repr2,"=",1); + repr2 = ldbCatStackValue(repr2,lua,-1); + repr2 = sdscatlen(repr2,"; ",2); + lua_pop(lua,1); /* Stack: table, key. Ready for next iteration. */ + expected_index++; + } + /* Strip the last " ;" from both the representations. */ + if (sdslen(repr1)) sdsrange(repr1,0,-3); + if (sdslen(repr2)) sdsrange(repr2,0,-3); + /* Select the right one and discard the other. */ + s = sdscatlen(s,"{",1); + s = sdscatsds(s,is_array ? repr1 : repr2); + s = sdscatlen(s,"}",1); + sdsfree(repr1); + sdsfree(repr2); + } + break; case LUA_TFUNCTION: case LUA_TUSERDATA: case LUA_TTHREAD: case LUA_TLIGHTUSERDATA: { - const void *p = lua_topointer(lua,-1); + const void *p = lua_topointer(lua,idx); char *typename = "unknown"; - if (t == LUA_TTABLE) typename = "table"; - else if (t == LUA_TFUNCTION) typename = "function"; + if (t == LUA_TFUNCTION) typename = "function"; else if (t == LUA_TUSERDATA) typename = "userdata"; else if (t == LUA_TTHREAD) typename = "thread"; else if (t == LUA_TLIGHTUSERDATA) typename = "light-userdata"; - s = sdscatprintf(s,"%s at %p",typename,p); + s = sdscatprintf(s,"%s@%p",typename,p); } break; default: - s = sdscat(s,"?"); + s = sdscat(s,""); break; } + return s; +} + +/* Produce a debugger log entry representing the value of the Lua object + * currently on the top of the stack. The element is ot popped nor modified. + * Check ldbCatStackValue() for the actual implementation. */ +void ldbLogStackValue(lua_State *lua, char *prefix) { + sds s = sdsnew(prefix); + s = ldbCatStackValue(s,lua,-1); ldbLog(s); - lua_pop(lua,1); } char *ldbRedisProtocolToHuman_Int(sds *o, char *reply); @@ -1875,6 +1926,7 @@ void ldbPrint(lua_State *lua, char *varname) { i++; if (strcmp(varname,name) == 0) { ldbLogStackValue(lua," "); + lua_pop(lua,1); return; } else { lua_pop(lua,1); /* Discard the var name on the stack. */ @@ -1954,6 +2006,7 @@ void ldbEval(lua_State *lua, sds *argv, int argc) { return; } ldbLogStackValue(lua," "); + lua_pop(lua,1); } /* Read debugging commands from client. */