Good day
I have a specific task to give an access of c++ std::map to lua scripts. Desired script syntax is glob["tag"] = "value" or glob("tag") = "value"
In research, have tried luabind binding
std::string & glob(const std::string &tag)
{
static std::string value;
return value;
}
...
luabind::module(&state)
[
def("glob", &glob, luabind::return_reference_to(result))
]
but after run of script listed below
glob("tag") = "asdasd"
print(glob("tag"))
got error [string "glob("tag") = "asdasd"..."]:1: unexpected symbol near '='
So, i'm waiting for your suggestions and opinions.
Thanks
Update
2lhf: Global variables data stored and serialized via c++ part and has to be accessed from lua.
luaState is created per script execution, and doesn't exist between executions. One of solution is create and fill global variables table before script execution and sync it with map after execution, but, i think it is slow enough. So, access via c-function with mentioned syntax will be appreciated.
glob("tag") = "asdasd" can never work, because it's not valid Lua syntax. glob["tag"] = "value" can work. You need to set glob as a userdata with index and newindex metamethods. I don't know anything about luabind, so I cannot help you there. But doing it using the standard Lua API is not hard. I just wonder why you need to export C++ map to Lua, when Lua has excellent associative arrays already.
Yep, metatable rules.
Just had to insert some c code get from samples
lua_createtable(&state, 0, 0);
lua_pushcfunction(&state, &getValue);
lua_setfield(&state, -2, "__index");
lua_pushcfunction(&state, &setValue);
lua_setfield(&state, -2, "__newindex");
lua_setmetatable(&state, -2);
lua_setglobal(&state, "global");
And everything works just fine, thanks
But here is another question: why i should use index == -2 for lua_setfield and lua_setmetatable?
Related
I'm using SQLite (3.6.4) from a C++ application (using the standard C api). My question is: once a query has been prepared, using sqlite3_prepare_v2(), and bound with parameters using sqlite3_bind_xyz() - is there any way to get a string containing the original SQL query?
The reason is when something goes wrong, I'd like to print the query (for debugging - this is an in-house developer only test app).
Example:
sqlite3_prepare_v2(db, "SELECT * FROM xyz WHERE something = ? AND somethingelse = ?", -1, &myQuery, NULL);
sqlite3_bind_text(myQuery, 1, mySomething);
sqlite3_bind_text(myQuery, 2, mySomethingElse);
// ....
// somewhere else, in another function perhaps
if (sqlite3_step(myQuery) != SQLITE_OK)
{
// Here i'd like to print the actual query that failed - but I
// only have the myQuery variable
exit(-1);
}
Bonus points if it could also print out the actual parameters that was bound. :)
You probably want to use sqlite3_trace
This will call a callback function (that you define) and on of the parameters is a char * of the SQL of the prepared statements (including bound parameters).
As per the comments in sqlite3.c (amalgamation), sqlite3_sql(myQuery) will return the original SQL text.
I don't see any function for finding the value bound at a particular index, but we can easily add one to the standard set of SQLite functions. It may look something like this:
const char* sqlite3_bound_value(sqlite3_stmt* pStmt, int index)
{
Vdbe *p = (Vdbe *)pStmt;
// check if &p->aVar[index - 1] points to a valid location.
return (char*)sqlite3ValueText(&p->aVar[index - 1], SQLITE_UTF8);
}
Well, the above code shows only a possible way sqlite3_bound_value() could be implemented. I haven't tested it, it might be wrong, but it gives certain hints on how/where to start.
Quoting the documentation:
In the "v2" interfaces, the prepared statement that is returned (the sqlite_stmt object) contains a copy of the original SQL text.
http://www.sqlite.org/c3ref/prepare.html
I'm working on improving the way we handle Lua scripting for robot players in Bitfighter. Currently, each robot gets its own L instance, and we're trying to get them to all share one by swapping out environment tables. Note that bots may be completely different scripts.
I realize that this method is deprecated in Lua 5.2, but we are currently using lua-vec, which still uses Lua 5.1. The game is written in C++.
So...
First we create an environment, and call it :
// Create a table with room for 0 array and 1 non-array elements
lua_createtable(L, 0, 1); // -- tab
// Set the globals table to handle any requests that the
// script's environment can't
lua_pushstring(L, "__index"); // -- tab, "__index"
lua_pushvalue(L, LUA_GLOBALSINDEX); // -- tab, "__index", _G
// Set table["__index"] = _G, pops top two items from stack
lua_settable(L, -3); // -- tab
// Store the new table in the retistry for future use
lua_setfield(L, LUA_REGISTRYINDEX, name); // -- <<empty stack>>
Later, we load some Lua code, and recall the environment table:
luaL_loadfile(L, "luascripts.lua");
lua_getfield(L, LUA_REGISTRYINDEX, name); // -- function, table
lua_setfenv(L, -2); // -- function
Then run the loaded code:
lua_pcall(L, 0, 0, 0);
When the loaded Lua tries to use a basic function, such as print, it fails with the error:
attempt to call global 'print' (a nil value)
But, the script can do the following:
__index["print"](12)
So... why can't we access print directly? What are we missing? Or is there a fundamentally better way to run multiple scripts in the same Lua instance?
Your code is close to correct, but contains several issues - You are attempting to do something that won't work, and your attempt did the wrong thing in the wrong way..
You are setting the function environment of the function to a table which looks like this:
{__index = _G}
Naturally, when you attempt to access print, it is not found in this table.
From your comments, I infer that actually wanted to set the __index field of the metatable of the environment table. That is, you wanted to make the environment tables be like t in the example below:
t = {}
setmetatable(t, {__index = _G})
(The C++ translation of this is fairly straightforward).
Don't do this. It will solve your immediate problem, but it will not provide sufficient sandboxing. Consider for example a script like this:
table.sort = 10
"table" will be found by in _G by the metatable event handler. sort is just an element of the table table, and so can be replaced with impunity. Now, other scripts will be unable to sort tables with table.sort.
One way to perform this kind of separation is to mediate access to all the global values through some sort of (possibly recursive) userdata with hand-written handlers for the relevant metatable events. (This way probably has the most potential for performance and control, but could be difficult to implement).
Another way is to create an environment table for for each script, and to copy the safe/sandboxed elements from the global table into this environment table (so that each script has a totally separate version of all the mutable elements of the global table).
I'm sorry I don't have time to properly explain my suggested solutions to your problem. I hope that I have given you somewhere to start. Feel free to come back and edit this to include the solution that you ultimately use.
In my C++ app, I have a string which contains XML data. Let's say I have an attribute Number1 and an attribute Number2.
I want to send that string to a Lua script and have it return a modified XML string. Let's say it adds a new attribute Product with the value of Number1 and Number2.
Is that easily done using C++/Lua, and if so how?
There are several methods to work with XML data listed at the Lua Users Wiki. The better options involve calls back to C (e.g. LuaXML and LuaExpat) so this only makes sense to do if there are other reasons to use Lua beyond just parsing XML.
Not a Lua user myself...but just browsing the documentation, it seems that you can use lua_pushstring() to put a copy of a null-terminated C string into the Lua stack:
http://pgl.yoyo.org/luai/i/lua_pushstring
Although there is no specific definition for things like lua_popstring() you can define something like that yourself:
std::string lua_popstring(lua_State *L)
{
std::string tmp = lua_tostring(L, lua_gettop(L));
lua_pop(L, 1);
return tmp;
}
With that in hand you should be able to modify the standard example for passing data into Lua and getting a result back for your purpose:
http://lua-users.org/wiki/SimpleLuaApiExample
You could do it similar to this (not this might not be 100 % correct due to being out of my mind and it doesn't include error handling):
lua_getglobal(L, "modifyXml"); // push function on stack by name
lua_pushstring(L, xml); // push the xml string as parameter
lua_pcall(L, 1, 1, 0); // call the function with 1 parameter, 1 return value and no error handler
strcpy(xml, lua_tostring(L, -1)); // get the top of the stack as a string and copy it to xml
lua_pop(xml, 1); // remove the string from the stack
The lua function called could look like this:
function modifyXml(xml)
-- do something with xml here
return xml
end
If you use Luabind it could look something like this in C++:
std::string result = luabind::call_function<std::string>(
"yourLuaFunction", inputXmlString);
You would implement yourLuaFunction in Lua of course, and require that Lua module from within your C++ program.
I am embedding Lua in a C++ application.
I have some modules (for now, simple .lua scripts) that I want to load programmatically, as the engine is being started, so that when the engine starts, the module(s) is/are available to scripts without them having to include a require 'xxx' at the top of the script.
In order to do this, I need to be able to programmatically (i.e. C++ end), ask the engine to load the modules, as part of the initialisation (or shortly thereafter).
Anyone knows how I can do this?
Hmm, I just use the simple approach: My C++ code just calls Lua's require function to pre-load the Lua scripts I want preloaded!
// funky = require ("funky")
//
lua_getfield (L, LUA_GLOBALSINDEX, "require"); // function
lua_pushstring (L, "funky"); // arg 0: module name
err = lua_pcall (L, 1, 1, 0);
// store funky module table in global var
lua_setfield (L, LUA_GLOBALSINDEX, "funky");
// ... later maybe handle a non-zero value of "err"
// (I actually use a helper function instead of lua_pcall
// that throws a C++ exception in the case of an error)
If you've got multiple modules to load, of course, put it in a loop... :)
The easiest way is to add and edit a copy of linit.c to your project.
I'm using SQLite (3.6.4) from a C++ application (using the standard C api). My question is: once a query has been prepared, using sqlite3_prepare_v2(), and bound with parameters using sqlite3_bind_xyz() - is there any way to get a string containing the original SQL query?
The reason is when something goes wrong, I'd like to print the query (for debugging - this is an in-house developer only test app).
Example:
sqlite3_prepare_v2(db, "SELECT * FROM xyz WHERE something = ? AND somethingelse = ?", -1, &myQuery, NULL);
sqlite3_bind_text(myQuery, 1, mySomething);
sqlite3_bind_text(myQuery, 2, mySomethingElse);
// ....
// somewhere else, in another function perhaps
if (sqlite3_step(myQuery) != SQLITE_OK)
{
// Here i'd like to print the actual query that failed - but I
// only have the myQuery variable
exit(-1);
}
Bonus points if it could also print out the actual parameters that was bound. :)
You probably want to use sqlite3_trace
This will call a callback function (that you define) and on of the parameters is a char * of the SQL of the prepared statements (including bound parameters).
As per the comments in sqlite3.c (amalgamation), sqlite3_sql(myQuery) will return the original SQL text.
I don't see any function for finding the value bound at a particular index, but we can easily add one to the standard set of SQLite functions. It may look something like this:
const char* sqlite3_bound_value(sqlite3_stmt* pStmt, int index)
{
Vdbe *p = (Vdbe *)pStmt;
// check if &p->aVar[index - 1] points to a valid location.
return (char*)sqlite3ValueText(&p->aVar[index - 1], SQLITE_UTF8);
}
Well, the above code shows only a possible way sqlite3_bound_value() could be implemented. I haven't tested it, it might be wrong, but it gives certain hints on how/where to start.
Quoting the documentation:
In the "v2" interfaces, the prepared statement that is returned (the sqlite_stmt object) contains a copy of the original SQL text.
http://www.sqlite.org/c3ref/prepare.html