lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


To all Lua experts,

I have successfully used the Lua 4.0 as an embeded scripting engine
for the Zeus editor and was looking to upgrading this engine to the
latest 5.0 release. I downloaded the 5.0 source and it built fine.

But I have run into a problem when I try to run a macro within the
Zeus editor.

A typical Zeus Lua macro looks like this:

  function key_macro()
    FileOpen() -- display the file open dialog
  end

  key_macro() -- run the macro

In the example above the FileOpen is a Zeus keyboard function that
will display the file open dialog.

The way this used to work for Lua version 4.x was I would trap the
getglobal using a tag method and then I would redirect this to the
zeus_function where I would test if a call to a Zeus builtin 
function was required.

So for example in the macro above the call to the FileOpen function
would be trapped by the hook and redirected to the Zeus editor which
would then display the file open dialog.

With the new 5.0 release this approach does not seem to be support?

The code that I use is achieve this is shown below. The areas marked
by "** 4.0 code change **" indicate code changes that I made to made
to support the new 5.0 release.

The problem I have run into is the fact that the lua_settagmethod 
function seems to have been removed. This function is used in the
zeus_lib_open method (see ??? in the code below) to setup the hook.

My question is this approach still possible with the 5.0 release?

If it is not what other alternatives could I use to achive the same
type of result?

Much thanks in advance.

Regards Jussi Jumppanen
              
void MacroLua::initialise()
{
  //-- set the call an line hooks
  /** 4.0 code change change to newer 5.0 code **/
  //lua_setcallhook(pLuaState, callhook);
  /** 4.0 code change change to newer 5.0 code **/
  //lua_setlinehook(pLuaState, linehook);

  lua_sethook(pLuaState, callhook, LUA_MASKCALL, 0);
  lua_sethook(pLuaState, linehook, LUA_MASKLINE, 0);

  //-- initialise the libraries
  lua_iolibopen(pLuaState);
  lua_strlibopen(pLuaState);
  lua_mathlibopen(pLuaState);
  lua_baselibopen(pLuaState);

  //-- special zeus library
  zeus_lib_open();
}

//-- Food for Thought
//-- ----------------
//-- Another way to avoid the global var is to setup a "getglobal" 
//-- tag method that simply returns the string and then setup 
//-- a "function" tag method that then searches this string in a 
//-- tables of yours.
//--
//-- So your zeus_hook can simply return the string it gets.
//-- Simply return 1 may do it.
//--
//-- Set zeus_function as the "function" tag method for strings 
//-- (LUA_TSTRING).

int MacroLua::zeus_hook(lua_State *pLuaState)
{
  //--
  //-- This method is the getglobal hook
  //--

  //-- This is the function that is to be run. Setup the szFunction
  //-- data as it is used by the zeus_function that is run next
  szFunction = luaL_check_lstr(pLuaState, 1, 0);

  //-- the callback function to run the function
  lua_pushcfunction(pLuaState, zeus_function);

  return 1;
}

void MacroLua::zeus_lib_open(void)
{
  //--
  //-- This method sets up the Zeus library and zeus function hook
  //--

  static struct luaL_reg zeus_lib[] =
  {
    //-- standard Zeus functions (non GUI)
    { "access"          , MacroLua::access         },
    { "getcwd"          , MacroLua::get_cwd        },
    { "setcwd"          , MacroLua::set_cwd        },
    { "strerror"        , MacroLua::strerror       },
    { "time"            , MacroLua::time           },

    //-- special hook functions
    { "ZeusHook"        , MacroLua::zeus_hook      },
    { "ZeusFunction"    , MacroLua::zeus_function  },
    { 0                 , 0                        },
  };

  //-- register the Zeus library functions
  /** 4.0 code change change to newer 5.0 code **/
  //luaL_openlib(pLuaState, zeus_lib, (sizeof(zeus_lib)/sizeof
  //             (zeus_lib[0])));
  luaL_openlib(pLuaState, "zeus", zeus_lib, 0);

  //-- add a hook for the "getglobal" tag
  lua_pushcfunction(pLuaState, zeus_hook);

//??? this is the problem ??? How to I setup the tag method for the
//??? getglobal tag ???
//  lua_settagmethod(pLuaState, LUA_TNIL, "getglobal");
}

int MacroLua::zeus_function(lua_State *pLuaState)
{
  //--
  //-- This method is used to check for Zeus functions
  //--

  //-- get the number of arguments on the stack
  int n = lua_gettop(pLuaState);

  //-- read the items off the stack
  for (int i = 1; i <= n; i++)
  {
    //-- add the arguments to the our argument list
    if (lua_isnumber(pLuaState, i))
    {
      argList.append(new xArgument(lua_tonumber(pLuaState, i)));
    }
    else if (lua_isstring(pLuaState, i))
    {
      argList.append(new xArgument(lua_tostring(pLuaState, i)));
    }
    else
    {
      //-- stop the macro
      lua_error(pLuaState, "Macro terminated!\n");

      return 0;
    }
  }

  int sCount = 0;

  //-- try to run the Zeus function (szFunction set by 
  //-- getglobal zeus_hook)
  if (xMacro::pInterface->run(szFunction))
  {
    //-- get then number of strings returned
    sCount = argReturn.count();

    //-- check if we are returning strings
    if (sCount == 0)
    {
      long lResult = argReturn;

      //-- must have just had a return code
      lua_pushnumber(pLuaState, lResult);

      //-- we have added an item to the stack
      sCount = 1;
    }
    else
    {
      //-- push the return values onto the stack
      for (int i = 0; i < sCount; ++i)
      {
        //-- check for a string type
        if (argReturn.isString())
        {
          //-- get the result
          const char *pszResult = argReturn[0];

          //-- give it to Lua
          lua_pushstring(pLuaState, pszResult);
        }
        else if (argReturn.isNumber())
        {
          //-- get the result
          long lReturn = argReturn;

          //-- give it to Lua
          lua_pushnumber(pLuaState, lReturn);
        }
        else
        {
          //-- stop the macro
          lua_error(pLuaState, "Macro terminated!\n");
        }
      }
    }
  }

  return sCount;
}