Merge branch 'lua-scripting' into screen-scripting-soc
authorRui Guo <firemeteor.guo@gmail.com>
Wed, 10 Jun 2009 07:42:55 +0000 (10 15:42 +0800)
committerRui Guo <firemeteor.guo@gmail.com>
Wed, 10 Jun 2009 07:42:55 +0000 (10 15:42 +0800)
With some local modifications. Still not work.

1  2 
src/lua.c

diff --cc src/lua.c
+++ b/src/lua.c
@@@ -78,8 -78,23 +78,54 @@@ extern struct layer *flayer
  static int LuaDispatch(void *handler, const char *params, va_list va);
  static int LuaRegEvent(lua_State *L);
  static int LuaUnRegEvent(lua_State *L);
 +static void LuaShowErr(lua_State *L);
  
 -    char *name;
+ enum
+ {
+   LUA_HANDLER_TYPE_N = 1,
+   LUA_HANDLER_TYPE_F
+ };
+ struct lua_handler
+ {
+   int type;
+   union
+   {
++    const char *name;
+     int reference;
+   } u;
+ };
++struct lua_handler *
++LuaAllocHandler(const char *name, int ref)
++{
++  struct lua_handler *lh;
++  lh = (struct lua_handler*) malloc(sizeof(struct lua_handler));
++  if (!lh)
++    return NULL;
++
++  if (name)
++    {
++      lh->type = LUA_HANDLER_TYPE_N;
++      lh->u.name = name;
++    }
++  else
++    {
++      lh->type = LUA_HANDLER_TYPE_F;
++      lh->u.reference = ref;
++    }
++
++  return lh;
++}
++
++void
++LuaFreeHandler(struct lua_handler **lh)
++{
++  if ((*lh)->type == LUA_HANDLER_TYPE_N)
++    Free((*lh)->u.name);
++  Free(*lh);
++}
++
  /** Template {{{ */
  
  #define CHECK_TYPE(name, type) \
@@@ -878,77 -864,19 +928,76 @@@ int LuaForeWindowChanged(void
    return LuaCallProcess("fore_changed", params);
  }
  
- char *
 -/*
 -int
 -LuaCommandExecuted(const char *command, const char **args, int argc)
++struct lua_handler *
 +LuaCheckHandler(lua_State *L, int idx, int reg)
  {
 -  if (!L)
 -    return 0;
 -  struct fn_def params[] = {
 -      {lua_pushstring, command},
 -      {push_stringarray, args},
 -      {NULL, NULL}
 -  };
 -  return LuaCallProcess("command_executed", params);
 -}*/
 +  if (lua_isstring(L, idx))
 +    {
 +      const char * handler;
 +      /* registered with func name.*/
 +      handler = luaL_checkstring(L, 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 SaveStr(handler);
++      return LuaAllocHandler(handler, 0);
 +    }
 +  else if (lua_isfunction(L, idx))
 +    {
 +      char buf[20];
 +      int key, htable;
 +      if (idx < 0)
 +        idx = lua_gettop(L) + 1 - idx;
 +
 +      luaL_getmetatable(L, "screen");
 +      lua_pushstring(L, "_handlers");
 +      lua_rawget(L, -2);
 +      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 */
 +          if (!reg)
 +            return NULL;
 +          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*/
 +        }
 +      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*/
 +            }
 +        }
 +
 +      lua_pop(L, 3);
-       snprintf(buf, 20, "%d", key);
-       return SaveStr(buf);
++      return LuaAllocHandler(NULL, key);
 +    }
 +  else
 +    luaL_error(L, "Handler should be a function or the name of function");
 +  return NULL;
 +}
  
  #define SEVNAME_MAX 30
  static int
@@@ -958,7 -886,8 +1007,8 @@@ LuaRegEvent(lua_State *L
     *        or: hook(event, handler, priv)
     *   returns: A ticket for later unregister. */
    int idx = 1, argc = lua_gettop(L);
 -  int priv = 31; /* Default privilege */
 -  struct lua_handler lh;
 +  unsigned int priv = 31; /* Default privilege */
++  struct lua_handler *lh;
  
    char *obj = NULL;
    const char *objname = "global";
    event = luaL_checkstring(L, idx++);
    snprintf(evbuf, SEVNAME_MAX, "%s_%s", objname, event);
  
 -  if (lua_isfunction(L, idx))
 -    {
 -      lua_pushvalue(L, idx);
 -      lh.u.reference = luaL_ref(L, LUA_REGISTRYINDEX);
 -      lh.type = LUA_HANDLER_TYPE_F;
 -      idx++;
 -    }
 -  else
 -    {
 -      lh.type = LUA_HANDLER_TYPE_N;
 -      lh.u.name = SaveStr(luaL_checkstring(L, idx++));
 -    }
 +  /* Check and get the handler */
-   handler = LuaCheckHandler(L, idx++, 1);
++  lh = LuaCheckHandler(L, idx++, 1);
++  if (!lh)
++    luaL_error(L, "Out of memory");
  
    StackDump(L, "In RegEvent\n");
  
        l = (struct listener *)malloc(sizeof(struct listener));
        if (!l)
          return luaL_error(L, "Out of memory");
-       l->handler = (void *)handler;
 -      l->handler = &lh;
        l->priv = priv;
        l->dispatcher = LuaDispatch;
        if (register_listener(sev, l))
          {
            free(l);
-           return luaL_error(L, "Handler %s has already been registered", handler);
 -        if (lh.type == LUA_HANDLER_TYPE_N)
 -          return luaL_error(L, "Handler %s has already been registered", lh.u.name);
++        if (lh->type == LUA_HANDLER_TYPE_N)
++          return luaL_error(L, "Handler %s has already been registered", lh->u.name);
+         else
+           return luaL_error(L, "Handler has already been registered");
          }
-       /*Return the handler for un-register*/
+       /* Return the handler for un-register */
 -      l->handler = malloc(sizeof(struct lua_handler));
 -      memcpy(l->handler, &lh, sizeof(struct lua_handler));
++      l->handler = lh;
        lua_pushlightuserdata(L, l);
      }
    else
@@@ -1050,7 -990,10 +1101,7 @@@ LuaUnRegEvent(lua_State *L
      }
    else
      {
-       free(l->handler);
 -      struct lua_handler *lh = l->handler;
 -      if (lh->type == LUA_HANDLER_TYPE_N)
 -      Free(lh->u.name);
 -      Free(l->handler);
++      LuaFreeHandler(&l->handler);
        unregister_listener(l);
        lua_pushboolean(L, 1);
      }