您的位置:首页 > 编程语言 > Lua

Calling lua functions from .lua's using handles?

2016-11-18 09:38 183 查看


Calling
lua functions from .lua's using handles?






up
vote0down
votefavorite
5

I'm working on a small project trying to integrate lua with c++. My problem however is as follows:

I have multiple lua scripts, lets call them s1.lua s2.lua and s3.lua. Each of these has the following functions: setVars() and executeResults().

Now I am able to to call a lua file through LuaL_dofile and immediately after use setVars() and/or executeResults(). The problem here however is that after I load s2.lua I can no longer call the functions of s1.lua. This would mean I have to redo the LuaL_dofile
on s1.lua to regain access to the function and by doing so I lose access to the functions in s2.lua.

Is there a way to simply load all lua files in a row, and afterwards start calling their functions at will? Something like s1->executeResults() s5->executeResults() s3->setVars() etc.

I currently already have a system in place using boost::filesystem to detect all lua files in a folder, I then save these files names in a vector and then simply iterate over the vector to load each lua file in a row.

Foregoing the filling of the vector with lua file names my plugin load function looks like this at the moment:
void Lua_plugin::load_Plugins(){
std::vector<std::string>::const_iterator it;
for (it=Lua_PluginList.begin(); it!=Lua_PluginList.end(); it++){
std::cout<<"File loading: " << *it << std::endl;
std::string filename =  *it;
std::string filepath = scriptdir+filename;
if (luaL_loadfile(L, filepath.c_str()) || lua_pcall(L, 0, 0, 0)) {
std::cout << "ScriptEngine: error loading script. Error returned was: " << lua_tostring(L, -1) << std::endl;
}
}
}


To make it a bit more clear, all I have in the .lua's is something like this:
-- s1.lua

setVars()
--do stuff
end

executeResults()
--dostuff
end


etc, but I would like to be able to call s1.lua's setVars() and s2.lua's setVars() after simply having loaded both in a row.

c++ lua lua-api
shareimprove
this question
edited Aug
10 '10 at 15:05





Andreas Bonini
23.5k20101140

asked Aug 7 '10 at 22:08





Karrok
55111

 add
a comment


3 Answers

activeoldestvotes

up vote5down
voteaccepted
This is effectively what gwell proposed using the C API:
#include <stdio.h>

#include "lua.h"

static void
executescript(lua_State *L, const char *filename, const char *function)
{
/* retrieve the environment from the resgistry */
lua_getfield(L, LUA_REGISTRYINDEX, filename);

/* get the desired function from the environment */
lua_getfield(L, -1, function);

return lua_call(L, 0, 0);
}

static void
loadscript(lua_State *L, const char *filename)
{
/* load the lua script into memory */
luaL_loadfile(L, filename);

/* create a new function environment and store it in the registry */
lua_createtable(L, 0, 1);
lua_getglobal(L, "print");
lua_setfield(L, -2, "print");
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, filename);

/* set the environment for the loaded script and execute it */
lua_setfenv(L, -2);
lua_call(L, 0, 0);

/* run the script initialization function */
executescript(L, filename, "init");
}

int
main(int argc, char *argv[])
{
lua_State *L;
int env1, env2;

L = (lua_State *) luaL_newstate();
luaL_openlibs(L);

loadscript(L, "test1.lua");
loadscript(L, "test2.lua");

executescript(L, "test1.lua", "run");
executescript(L, "test2.lua", "run");
executescript(L, "test2.lua", "run");
executescript(L, "test1.lua", "run");

return 0;
}


Test scripts:
-- test1.lua
function init() output = 'test1' end
function run() print(output) end

-- test2.lua
function init() output = 'test2' end
function run() print(output) end


Output:
test1
test2
test2
test1


I omitted all error handling for brevity, but you'll want to check the return value of 
luaL_loadfile
 and
use 
lua_pcall
 instead
of 
lua_call
.

shareimprove
this answer
answered Aug 9 '10 at 14:39





Judge Maygarden
18.5k55184

 add
a comment





up vote1down
vote
The 
setfenv()
 function
can be used to create a sandbox or environment for each file loaded.

This example shows that all three files could be loaded with conflicting functions and that the functions can be called in any order. Similar code could be written in C++. This example only exports the print function to each environment, more might be needed
in your scenario.
function newEnv()
-- creates a simple environment
return {["print"]=print}
end

local e={} -- environment table
local c    -- chunk variable

-- first instance
c = loadstring([[function f() print("1") end]])
e[#e+1] = newEnv()
setfenv(c, e[#e]) -- set the loaded chunk's environment
pcall(c) -- process the chunk (places the function into the enviroment)

-- second instance
c = loadstring([[function f() print("2") end]])
e[#e+1] = newEnv()
setfenv(c, e[#e])
pcall(c)

-- third instance
c = loadstring([[function f() print("3") end]])
e[#e+1] = newEnv()
setfenv(c, e[#e])
pcall(c)

pcall(e[3].f) --> 3
pcall(e[2].f) --> 2
pcall(e[1].f) --> 1
pcall(e[1].f) --> 1
pcall(e[2].f) --> 2
pcall(e[3].f) --> 3


shareimprove
this answer
answered Aug 8 '10 at 2:58





gwell
2,1101218

 
 
First off, thanks! I was looking around in the c++ part of lua and I'm not able to find which function would replace
the setfenv() of lua in a c++ environment. This mostly because I would like to retain addon/plugin control in my c++ code (aside from being a bit more versed in c++ compared to lua). And would I be correct in assuming that I could then incorporate the environment
creation in my Load_Plugins() function? Having the environment list usable by other parts of the c++ code? Thanks in advance – Karrok Aug
8 '10 at 3:42
 
Correction found pgl.yoyo.org/luai/i/lua_setfenv Darting
though the lua-users.org listings it would suggest this function is deprecated though, but I'll try it anyway :) – Karrok Aug
8 '10 at 4:04
 
Deprecation would depend on the version of Lua you are using. 
setfenv()
 will
be deprecated in 5.2. See corsix.org/content/look-lua-52-work3 – gwell Aug
8 '10 at 4:15
 
Some trying later, and I can't for the life of me figure out how the above lua code would translate into c++ :(. I'm
assuming I'm not using the lua_setfenv and lua_getfenv correctly since the application simply crashes. – Karrok Aug
8 '10 at 4:55
add
a comment
up vote1down
vote
You could create a new state 
lua_newstate()
 for
each file. This would be easier than my previous answer. However, it may have a performance penalty.

shareimprove
this answer
answered Aug 9 '10 at 2:54





gwell
2,1101218

 
 
Well if creating the new state only once for each lua file isn't too big a performance penalty then it should not be
a problem. The secondary and following access to the states should not occur that often. I think i'll try the newstate thingy because I still can't get the lua_setfenv to work without it crashing the app :( Thanks again :)– Karrok Aug
9 '10 at 4:35
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: