Restructure the func register code.
authorRui Guo <firemeteor.guo@gmail.com>
Wed, 10 Jun 2009 14:02:18 +0000 (10 22:02 +0800)
committerRui Guo <firemeteor.guo@gmail.com>
Wed, 10 Jun 2009 14:02:18 +0000 (10 22:02 +0800)
Now we have a unified Lua function registration mechanism. User can register
with the function name, but the name is always resolved to the Lua function
itself. Typo is detected at this stage. The Lua function is then mapped to a
unique key, managed with reference counting.

src/lua.c

index ac4c59f..1c07288 100644 (file)
--- a/src/lua.c
+++ b/src/lua.c
@@ -960,88 +960,127 @@ int LuaForeWindowChanged(void)
   return LuaCallProcess("fore_changed", params);
 }
 
+int
+LuaPushHTable(lua_State *L, int screen, const char * t)
+{
+  lua_pushstring(L, t);
+  lua_rawget(L, screen);
+  /* FIXME: Do we need to balance the stack here? */
+  if (lua_isnil(L, -1))
+    luaL_error(L, "Fatal! Fail to get function registeration table!");
+  return lua_gettop(L);
+}
+
+int
+LuaFuncKey(lua_State *L, int idx)
+{
+  int key, funckey, sc;
+  luaL_getmetatable(L, "screen");
+  sc = lua_gettop(L);
+  funckey = LuaPushHTable(L, sc, "_funckey");
+
+  lua_pushvalue(L, idx);
+  lua_gettable(L, funckey);/*funckey[func] ==?*/
+  if (lua_isnil(L, -1))
+    {
+      /* Not found, alloc a new key */
+
+      /*funckey[key] = 1*/
+      lua_pushinteger(L, 1);
+      key = luaL_ref(L, funckey);
+
+      /*funckey[func]=key*/
+      lua_pushvalue(L, idx);
+      lua_pushinteger(L, key);
+      lua_settable(L, funckey); 
+
+      int keyfunc = LuaPushHTable(L, sc, "_keyfunc");
+      /*keyfunc[key] = func*/
+      lua_pushinteger(L, key);
+      lua_pushvalue(L, idx);
+      lua_settable(L, keyfunc);
+
+      lua_pop(L, 1);
+    }
+  else
+    key = lua_tointeger(L, -1);/*key = funckey[func]*/
+
+  lua_pop(L, 3);
+  return key;
+}
+
+void
+LuaHRef(lua_State *L, int key, int reg)
+{
+  int funckey, keyfunc, cnt, sc, idx;
+  luaL_getmetatable(L, "screen");
+  sc = lua_gettop(L);
+  funckey = LuaPushHTable(L, sc, "_funckey");
+  keyfunc = LuaPushHTable(L, sc, "_keyfunc");
+
+  lua_rawgeti(L, keyfunc, key);
+  idx = lua_gettop(L);
+
+  lua_rawgeti(L, funckey, key);
+  cnt = lua_tointeger(L, -1);/*cnt = htable[key]*/
+  if (!reg && cnt <= 1)
+    {
+      /*release the last reference*/
+      luaL_unref(L, funckey, key);
+      lua_pushvalue(L, idx);
+      lua_pushnil(L);
+      lua_settable(L, funckey); /*htable[func]=key*/
+    }
+  else
+    {
+      lua_pushinteger(L, key);
+      lua_pushinteger(L, reg? cnt + 1 : cnt - 1);
+      lua_settable(L, funckey); /*htable[key] = cnt + 1*/
+    }
+  lua_pop(L, 3);
+}
+
+void
+LuaHSetName(lua_State *L, int key, int name)
+{
+  int keyfunc, sc;
+  luaL_getmetatable(L, "screen");
+  sc = lua_gettop(L);
+  keyfunc = LuaPushHTable(L, sc, "_keyfunc");
+
+  lua_rawgeti(L, keyfunc, key);
+  lua_pushvalue(L, name);
+  lua_rawset(L, keyfunc);
+
+  lua_pop(L, 2);
+}
+
 struct lua_handler *
 LuaCheckHandler(lua_State *L, int idx, int reg)
 {
+  int name = 0, key, sc;
   if (lua_isstring(L, idx))
     {
       const char * handler;
       /* registered with func name.*/
       handler = luaL_checkstring(L, idx);
+      name = idx++;
       lua_getfield(L, LUA_GLOBALSINDEX, handler);
       if (!lua_isfunction(L, -1))
         luaL_error(L, "The specified handler %s in param #%d is not a function", handler, idx);
-      lua_pop(L, 1);
-      return LuaAllocHandler(handler, 0);
     }
-  else if (lua_isfunction(L, idx))
-    {
-      int key, htable;
-      if (idx < 0)
-        idx = lua_gettop(L) + 1 - idx;
-
-      luaL_getmetatable(L, "screen");
-      lua_pushstring(L, "_funckey");
-      lua_rawget(L, -2);
-      /* FIXME: Do we need to balance the stack here? */
-      if (lua_isnil(L, -1))
-        luaL_error(L, "Fatal! Should not happen! Fail to get global handler table!");
-      /* Map func to unique key and do reference count */
-      htable = lua_gettop(L);
-      lua_pushvalue(L, idx);
-      lua_gettable(L, htable);/*htable[func] ==?*/
-      if (lua_isnil(L, -1))
-        {
-          /* not found */
-          int kf;
-          if (!reg)
-            {
-              lua_pop(L, 3); 
-              return NULL;
-            }
-          lua_pushstring(L, "_keyfunc");
-          lua_rawget(L, -4);
-          kf = lua_gettop(L);
-
-          lua_pushinteger(L, 1);
-          key = luaL_ref(L, htable); /*htable[key] = 1*/
-          lua_pushvalue(L, idx);
-          lua_pushinteger(L, key);
-          lua_settable(L, htable); /*htable[func]=key*/
-
-          lua_pushinteger(L, key);
-          lua_pushvalue(L, idx);
-          lua_settable(L, kf);
-          lua_remove(L, kf);
-        }
-      else
-        {
-          int cnt;
-          key = lua_tointeger(L, -1);/*key = htable[func]*/
-          lua_gettable(L, htable);
-          cnt = lua_tointeger(L, -1);/*cnt = htable[key]*/
-          if (!reg && cnt <= 1)
-            {
-              /*release the last reference*/
-              luaL_unref(L, htable, key);
-              lua_pushvalue(L, idx);
-              lua_pushnil(L);
-              lua_settable(L, htable); /*htable[func]=key*/
-            }
-          else
-            {
-              lua_pushinteger(L, key);
-              lua_pushinteger(L, reg? cnt + 1 : cnt - 1);
-              lua_settable(L, htable); /*htable[key] = cnt + 1*/
-            }
-        }
+  else if (!lua_isfunction(L, idx))
+    luaL_error(L, "Handler should be a function or the name of function");
 
-      lua_pop(L, 3);
-      return LuaAllocHandler(NULL, key);
+  sc = lua_gettop(L);
+  key = LuaFuncKey(L, idx );
+  LuaHRef(L, key, reg);
+  if (name)
+    {
+      LuaHSetName(L, key, name);
+      lua_pop(L, 1);
     }
-  else
-    luaL_error(L, "Handler should be a function or the name of function");
-  return NULL;
+  return LuaAllocHandler(NULL, key);
 }
 
 #define SEVNAME_MAX 30