C calling Lua with arguments

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

C calling Lua with arguments

Milan Obuch
Hi,

I am starting to use Lua as scripting engine for a Claws Mail plugin.
While I was able to create something basically working quite easily in
short time, there are some troubles I found no solution for, yet.

Some background - why?

I am long time Claws Mail user. At some point I started to use Python
plugin for some tasks, which worked to my satisfaction.

World did not stop turning, Python 2 is being replaced with Python 3.
Current Claws Mail is GTK2 based which basically means Python 2 with
PyGTK binding... and it does not work in current FreeBSD ports
framework, there is no port actually for the plugin.

I tried development version of Claws Mail with GTK3 which has Python
plugin ported to Python 3, but this require other GTK binding for which
there is no FreeBSD port. Also this new version is not yet fully
polished, there are some small issues.

Then I decided to try something new. It was possible to create new
plugin, I did manage to put some patches together to hook everything
into build process and it basically works.

The problem - what?

In Claws Mail there are some places where it is possible to execute
external scripts. With scripting plugin one can use some script invoked
when mail compose windows is opened or when a button in toolbar is
pressed, or when some action in menu is selected.

Currently I know no way how can I differentiate which compose window my
script is being called from in case of multiple windows being open.
Basically everything ends up with question how can I call a Lua script
with an argument.

How it works, now?

When plugin is being loaded, a function is registered with Claws Mail
hook mechanism which is to be called on creating mail compose window.
When I try to create new message or reply to existing one, compose
window is being created and my function is being called with an
argument - C pointer to structure describing the window. In my C
function I use luaL_dofile() to load a script from file and execute it.

And here comes the question - how can I use this C pointer as an
argument for my script? I know I can do

lua_pushlightuserdata(L,(void *)compose_window_argument);
luaL_dofile(L,"my_script_file");
lua_pop(L,1);

but I found no way to access this argument from my_script_file. As an
ugly workaround, not working properly with more than one opened window
at the same time, I use

set_compose_window(compose_window_argument);
luaL_dofile(L,"my_script_file");

where in set_compose_window I just store argument given to some static
variable which I then access with function

static int _get_compose_self(lua_State *L)
{
 lua_pushlightuserdata(L,(void *)compose);
 return 1;
}

called from Lua side as

local compose = compose_window.get()

This works with script being called on windows create, but in case of
an action executed via some menu item or toolbar button value got this
way is not necessarily correct.

Could somebody help me with this issue? Is it possible to do it with
push/dofile/pop sequence as outlined above?

Regards,
Milan
Reply | Threaded
Open this post in threaded view
|

Re: C calling Lua with arguments

Sean Conner
It was thus said that the Great Milan Obuch once stated:
> Hi,

  Hello.

> When plugin is being loaded, a function is registered with Claws Mail
> hook mechanism which is to be called on creating mail compose window.
> When I try to create new message or reply to existing one, compose
> window is being created and my function is being called with an
> argument - C pointer to structure describing the window. In my C
> function I use luaL_dofile() to load a script from file and execute it.
>
> And here comes the question - how can I use this C pointer as an
> argument for my script? I know I can do
>
> lua_pushlightuserdata(L,(void *)compose_window_argument);
> luaL_dofile(L,"my_script_file");
> lua_pop(L,1);
>
> but I found no way to access this argument from my_script_file.

  There is a way, but you can't use luaL_dofile().  First off, change the C
code to:

        int rc;

        rc = luaL_loadfile(L,"my_script_file");
        if (rc != LUA_OKAY) error();
        lua_pushlightuserdata(L,(void *)compose_window_argument);
        rc = lua_pcall(L,1,LUA_MULTRET,0);
        if (rc != LUA_OKAY) error();

(minimal error checking added---handle as appropriate).  Then in your
script:

        local window = ...

or

        local window = select(1,...)

  When Lua loads any code, it is compiled and returned as a function, which
when run, will do the action of the script.  As long as there are parameters
on the stack, the script can reference them via '...' (or select()).

  -spc
Reply | Threaded
Open this post in threaded view
|

Re: C calling Lua with arguments

Milan Obuch
On Fri, 5 Jun 2020 02:48:03 -0400, Sean Conner <[hidden email]> wrote:

> It was thus said that the Great Milan Obuch once stated:
> > Hi,  
>
>   Hello.
>
> > When plugin is being loaded, a function is registered with Claws
> > Mail hook mechanism which is to be called on creating mail compose
> > window. When I try to create new message or reply to existing one,
> > compose window is being created and my function is being called
> > with an argument - C pointer to structure describing the window. In
> > my C function I use luaL_dofile() to load a script from file and
> > execute it.
> >
> > And here comes the question - how can I use this C pointer as an
> > argument for my script? I know I can do
> >
> > lua_pushlightuserdata(L,(void *)compose_window_argument);
> > luaL_dofile(L,"my_script_file");
> > lua_pop(L,1);
> >
> > but I found no way to access this argument from my_script_file.  
>
>   There is a way, but you can't use luaL_dofile().  First off, change
> the C code to:
>
> int rc;
>
> rc = luaL_loadfile(L,"my_script_file");
> if (rc != LUA_OKAY) error();
> lua_pushlightuserdata(L,(void *)compose_window_argument);
> rc = lua_pcall(L,1,LUA_MULTRET,0);
> if (rc != LUA_OKAY) error();
>
> (minimal error checking added---handle as appropriate).  Then in your
> script:
>
> local window = ...
>
> or
>
> local window = select(1,...)
>
>   When Lua loads any code, it is compiled and returned as a function,
> which when run, will do the action of the script.  As long as there
> are parameters on the stack, the script can reference them via '...'
> (or select()).
>

Now looking in Lua 5.2 Reference Manual, entry for luaL_loadfile -
equivalent for luaL_loadfilex with mode equal NULL. Now another
redirection for mode in entry for luaL_loadfilex - to lua_load and
finally there to load... somehow hard to follow :) Anyway, now I
understand first call plus next line error handling. Now lua_pcall...
look for lua_call as well...

OK, understand, I think. Thank you!

Regards,
Milan
Reply | Threaded
Open this post in threaded view
|

Re: C calling Lua with arguments

Philippe Verdy-2
You could also use a convention that will pass a Lua script you compose:
The script will "require()" the Lua script that will return a Lua "function()" to be called with the parameters you want to pass.
Basically you build this string in C: 'require('..script name..')('..parameters..')'
Then run this script from the Lua instance you create in C.

Le ven. 5 juin 2020 à 11:00, Milan Obuch <[hidden email]> a écrit :
On Fri, 5 Jun 2020 02:48:03 -0400, Sean Conner <[hidden email]> wrote:

> It was thus said that the Great Milan Obuch once stated:
> > Hi, 
>
>   Hello.
>
> > When plugin is being loaded, a function is registered with Claws
> > Mail hook mechanism which is to be called on creating mail compose
> > window. When I try to create new message or reply to existing one,
> > compose window is being created and my function is being called
> > with an argument - C pointer to structure describing the window. In
> > my C function I use luaL_dofile() to load a script from file and
> > execute it.
> >
> > And here comes the question - how can I use this C pointer as an
> > argument for my script? I know I can do
> >
> > lua_pushlightuserdata(L,(void *)compose_window_argument);
> > luaL_dofile(L,"my_script_file");
> > lua_pop(L,1);
> >
> > but I found no way to access this argument from my_script_file.   
>
>   There is a way, but you can't use luaL_dofile().  First off, change
> the C code to:
>
>       int rc;
>
>       rc = luaL_loadfile(L,"my_script_file");
>       if (rc != LUA_OKAY) error();
>       lua_pushlightuserdata(L,(void *)compose_window_argument);
>       rc = lua_pcall(L,1,LUA_MULTRET,0);
>       if (rc != LUA_OKAY) error();
>
> (minimal error checking added---handle as appropriate).  Then in your
> script:
>
>       local window = ...
>
> or
>
>       local window = select(1,...)
>
>   When Lua loads any code, it is compiled and returned as a function,
> which when run, will do the action of the script.  As long as there
> are parameters on the stack, the script can reference them via '...'
> (or select()).
>

Now looking in Lua 5.2 Reference Manual, entry for luaL_loadfile -
equivalent for luaL_loadfilex with mode equal NULL. Now another
redirection for mode in entry for luaL_loadfilex - to lua_load and
finally there to load... somehow hard to follow :) Anyway, now I
understand first call plus next line error handling. Now lua_pcall...
look for lua_call as well...

OK, understand, I think. Thank you!

Regards,
Milan
Reply | Threaded
Open this post in threaded view
|

Re: C calling Lua with arguments

Milan Obuch
On Fri, 5 Jun 2020 11:41:18 +0200, Philippe Verdy <[hidden email]>
wrote:

> You could also use a convention that will pass a Lua script you
> compose: The script will "require()" the Lua script that will return
> a Lua "function()" to be called with the parameters you want to pass.
> Basically you build this string in C:
> 'require('..script name..')('..parameters..')'
> Then run this script from the Lua instance you create in C.
>

Thanks for tip, maybe I'll try it some day. For now, Sean's
recommendation works quite well for me and my problem with incorrect
value is solved.

Slightly OT, shameless advert:

If anybody here is using Claws Mail and would like to try some Lua
scripting, please let me know. My Lua plugin is still in early stage of
development, but I have working framework which can be extended with
more functionality.

Regards,
Milan