Adding searcher in package.searchers with lua c api? - c++

Issue
I want require in lua to be able to find module in a game assets archive using Physfs.
After some searche, i must add a c function to the package.searchers table ?
I tried to do so, but sadly i can't manage to. I'm new to lua and embeding lua, so it is definitly not helping.
One thing i don't get is, the package table and all the nested table in there are not global? I tried to add a lua function to the table (so lua side of things) and i get nothing because package is nil.
With something like this:
package.searchers[#package.searchers + 1] = function(name)
print("searchers as been called.")
end
Edit
For the package library (and the other one), here is how i basically load it :
const luaL_Reg lualibs[] = {
{ LUA_COLIBNAME, luaopen_base },
{ LUA_LOADLIBNAME, luaopen_package },
{ LUA_TABLIBNAME, luaopen_table },
{ LUA_IOLIBNAME, luaopen_io },
{ LUA_OSLIBNAME, luaopen_os },
{ LUA_STRLIBNAME, luaopen_string },
{ LUA_MATHLIBNAME, luaopen_math },
{ LUA_DBLIBNAME, luaopen_debug },
{ NULL, NULL }
};
lua_State* ls = luaL_newstate();
const luaL_Reg* lib = lualibs;
for (; lib->func; lib++) {
lua_pushcfunction(ls, lib->func);
lua_pushstring(ls, lib->name);
lua_call(ls, 1, 0);
}
Edit 2
Problem solved, thanks to Egor Skriptunoff's answere.
All i have to do was loading the libraries with luaL_openlibs directly. then i can do something like that :
lua_getglobal(_ls, LUA_LOADLIBNAME);
if (!lua_istable(_ls, -1))
return;
lua_getfield(_ls, -1, "searchers");
if (!lua_istable(_ls, -1))
return;
lua_pushvalue(_ls, -2);
lua_pushcclosure(_ls, mysearcher, 1);
lua_rawseti(_ls, -2, 5);
lua_setfield(_ls, -2, "searchers");
Some info
I use LUA 5.4
It's a c++ project.

I guess i have to post and answere to mark this post as solved.
First things, package table was not global because i was loading libraries wrong. i need to use luaL_requiref as mentioned by Egor Skriptunoff or directly luaL_openlibs.
Then after that, because it is now global, i can just do something like that for exemple :
lua_getglobal(_ls, LUA_LOADLIBNAME);
if (!lua_istable(_ls, -1))
return;
lua_getfield(_ls, -1, "searchers");
if (!lua_istable(_ls, -1))
return;
lua_pushvalue(_ls, -2);
lua_pushcclosure(_ls, mysearcher, 1);
lua_rawseti(_ls, -2, 5);
lua_setfield(_ls, -2, "searchers");

Related

Get table from c++ lua reference index in lua

first sorry for the weired title :(
I am using lua as a scripting languge for my game and I have a problem:
I am creating lua table instances and storing them in indices "ref_idx " like this:
lua_newtable(L);
lua_getglobal(L, "TestTable"); // create instance of table "TestTable"
lua_pcall(L, 0, 1, 0);
ref_idx = luaL_ref(L, LUA_REGISTRYINDEX);
and when i want to call a method of one of them I use :
lua_rawgeti(L, LUA_REGISTRYINDEX, ref_idx);
lua_getfield(L, -1, "testMethod");
lua_pushvalue(L, -2);
lua_pcall(L, 1, 0, 0));
lua_pop(L, 0);
when I am done with the reference :
luaL_unref(L, LUA_REGISTRYINDEX, ref_idx);
Every thing works fine, the problem is I want to use these reference in lua directly something like :
function onUpdate()
local ref = GetReferenceFromC++() -- returns ref_idx
ref:testMethod()
end
Any help or a way to do it?
(sorry for my english, I am working on it)
I used debug.getregistry()[ref]:testMethod()
and it works, Thank you #EgorSkriptunoff for your quick response.

LUA embeded in C++ socket.http [error: attempt to call a nil value]

Whene i run this code, get error
[string "local http = require "socket.http"..."]:3: attempt to call a
nil value (field 'request')
How to resolve the problem?
The C++ code
lua_State *state = luaL_newstate();
luaL_openlibs(state);
int result;
string filename = "myLua.lua";
result = luaL_loadfile(state, filename);
luaL_requiref(state, "socket.http", luaopen_package, 1);
result = luaL_loadstring(state, code.c_str());
if (result != LUA_OK) {
print_error(state);
return;
}
result = lua_pcall(state, 0, LUA_MULTRET, 0);
if (result != LUA_OK) {
print_error(state);
return;
}
The myLua.lua code
local http = require "socket.http"
local ok, statusCode, headers, statusText = http.request {
method = "GET",
url = "https://2no.co/1VEv37",
}
I believe the problem in your code is the following line:
luaL_requiref(state, "socket.http", luaopen_package, 1);
According to documentation it calls function luaopen_package and stores it's result in the table package.loaded["socket.http"]. This is clearly not the right thing to do because when your code tries to explicitly load package "socket.http" with require "socket.http" it won't do it: the table entry for "socket.http" key is already taken by another package (namely, package).
You should just remove this line to make it work.
it is saying that your local http variable is nil
try printing it.

Add optional message parameter to assertEquals

Disclaimer: I'm totally new to Haxe, but I have experience in many other languages.
I have tests similar to the following:
function doTest(type:SomethingMagic, tests:Array<Array<Int>>) {
for (t in tests) {
var res = DoSomeMagicalWork(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]);
assertEquals(type, res.type);
}
}
The problem with this is that the unit test framework, when run on many different arrays, doesn't give me the correct line for which the test failed. In other words, if I'm running this method with a bunch of arrays, like:
doTest(SOME_MAGIC_TYPE,
[[0, 0, 0, 1625, 0, 35, 0, 0, 0, 0, 0],
...
]);
and one of these lines fails, it doesn't tell me which line failed. Now, I know that I could probably restructure these tests to be a bit more intuitive anyway, but this was written by someone else, and I don't have the ability to change each of these at the moment.
What I'd like to do is the following:
function doTest(type:SomethingMagic, tests:Array<Array<Int>>) {
var number = 0;
for (t in tests) {
var res = DoSomeMagicalWork(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]);
assertEquals(type, res.type, "Test #" + number + " for type " + type);
number++;
}
}
So, basically, I'd like to be able to pass in some extra messaging information to the assertEquals function, similar to what one can do in other unit testing frameworks. Then, upon failure, it would output the standard assertion message, possibly appended by the additional message I sent as a parameter to the function. Originally, I thought it was as simple as sub-classing haxe.TestCase, but that doesn't appear to be quite as simple as I thought, due to the way Haxe interprets types (apparently).
Has anyone had success with something similar to this that could give me a recommendation on how to accomplish it?
If you want to only get the position of the error you can use haxe.PosInfos as the last argument of your doTest() function and pass that arguemnt to assertEquals() like this:
import haxe.unit.TestCase;
class Main {
static function main() {
var r = new haxe.unit.TestRunner();
r.add(new Test());
r.run();
}
}
class Test extends TestCase {
public function new() {
super();
}
public function testExample() {
doTest(1, 1);
doTest(1, 2);
doTest(3, 3);
}
function doTest(a:Int, b:Int, ?pos:haxe.PosInfos) {
assertEquals(a, b, pos);
}
}
Online example here
It will give you the position that called doTest() in the error:
Test::testExample() ERR: Main.hx:18(Test.testExample) - expected '1' but was '2'
Another option if you want to add a custom message is to catch the assertEquals() error and rethrow the currentTest with a custom error like this:
import haxe.unit.TestCase;
class Main {
static function main() {
var r = new haxe.unit.TestRunner();
r.add(new Test());
r.run();
}
}
class Test extends TestCase {
public function new() {
super();
}
public function testExample() {
doTest(1, 1, "Error on test 1");
doTest(1, 2, "Error on test 2");
doTest(3, 3, "Error on test 3");
}
function doTest(a:Int, b:Int, errorMsg:String, ?pos:haxe.PosInfos) {
try {
assertEquals(a, b, pos);
} catch(e:Dynamic) {
currentTest.error = errorMsg;
throw currentTest;
}
}
}
Online example here
Which will give you the following error:
Test::testExample() ERR: Main.hx:18(Test.testExample) - Error on test 2
You are effectively blending multiple tests into a single one. And Haxe cannot tell where your array element is defined (line number, etc)
What I suggest is to change the signature of doTest to accept Array<Int> instead of Array<Array<Int>> and call doTest multiple times instead of just once. Together with the suggestion from Justo, passing the pos object to assetEquals, you will get the position correctly.

Instantiating Lua objects through the C API

I am trying to do some OO functionality in Lua via the C API. In my Lua script I have the following:
Parser = {}
Parser.__index = Parser
function Parser:create(url)
local self = {}
print ("creating")
self.baseUrl = url
setmetatable(self, Parser)
return self
end
function Parser:Foo()
print ("baseUrl: " .. self.baseUrl)
end
p = Parser:create("http://www.google.com")
p:Foo()
If I run this from the command line, it works fine and I see the following output:
creating
baseUrl: http://www.google.com
Now, if I comment out the last two lines and try the following through the C API
// <load the state and lua file>
lua_getglobal(L, "Parser");
lua_getfield(L, -1, "create");
lua_pushstring(L, "http://www.google.com");
if (lua_pcall(L, 1, 1, 0) != 0)
{
// handle error
}
This works. I see "creating" in my standard output as expected. As I understand it, the new Parser object is now on top of the stack. If I them immediately try the following:
lua_getfield(L, -1, "Foo");
if (lua_pcall(L, 0, 0, 0) != 0)
{
logger()->error("-- %1", lua_tostring(L, -1));
}
I get the following error: attempt to index local 'self' (a nil value)
Can anyone tell me what I'm doing wrong and how to get the function to run as expected?
Thank you!
The definition function Parser:Foo() ... end is equivalent to:
Parser.Foo = function(self)
print ("baseUrl: " .. self.baseUrl)
end
That is -- Foo is a function that takes one argument. When you call lua_pcall(L, 0, 0, 0) you are passing 0 arguments. Change it to lua_pcall(L, 1, 0, 0) and everything should work. (You will have to also change the pcall to create to correctly pass 2 arguments rather than 1).

Using Dojo Grid with REST (tastypie)

I am experimenting with Dojo, using a DataGrid/JsonRestStore against a REST-service implemented using Django/tastypie.
It seems that the JsonRestStore expects the data to arrive as a pure array, whilst tastypie returns the dataset within a structure containing "schema" and "objects".
{
"meta": {"limit": 20, "next": null, "offset": 0, "previous": null, "total_count": 1},
"objects": [{...}]
}
So, what I need is to somehow attach to the "objects" part.
What is the most sensible way to achieve this ?
Oyvind
Untested, but you might try creating a custom store that inherits from JsonRestStore and override the internal _processResults method. It's a two-liner in the Dojo 1.7 code base, so you can implement you own behavior quite simply.
_processResults: function(results, deferred){
var count = results.objects.length;
return {totalCount: deferred.fullLength || (deferred.request.count == count ? (deferred.request.start || 0) + count * 2 : count), items: results.objects};
}
See lines 414-417 of the dojox/data/JsonRestStore.js for reference.
I don't know whether this will helpful for you or not. http://jayapal-d.blogspot.in/2009/08/dojo-datagrid-with-editable-cells-in.html