I'm trying to write Lua bindings so that one can call arbitrary functions on a userdata. An MCV example I've been working on is below.
In summary: we have the C function newarray pushed to a table in the Lua globals so that one can create a new array object. Suppose that the array is a database record. I have two kinds of operation that I want to perform on it after generating it with newarray (for this bad example): accessing an element, and destroying the object.
Since I don't know how many elements there will be (in a real world example), I decide to make __index a function and use an if-statement to determine if the function was "destroy" or anything else (i.e. "give me this element"). If it was "destroy", delete the object; otherwise, return the requested element.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#define TEST_METATABLE "_test_mt"
typedef struct
{
int* array;
} array_t;
int newArray(lua_State* L)
{
assert(lua_gettop(L) == 0);
array_t* array = lua_newuserdata(L, sizeof(array_t));
array->array = malloc(sizeof(int) * 10);
for (int i = 0; i < 10; i++)
array->array[i] = i;
/* Set metatable */
lua_getfield(L, LUA_REGISTRYINDEX, TEST_METATABLE);
lua_setmetatable(L, -2);
return 1;
}
int indexFunc(lua_State* L)
{
int argc = lua_gettop(L);
array_t* array = luaL_checkudata(L, 1, TEST_METATABLE);
const char* key = luaL_checkstring(L, 2);
int ret = 0;
if (!strcmp(key, "destroy"))
{
if (argc != 2)
{
lua_settop(L, 0);
luaL_error(L, "Invalid arguments");
}
if (array->array)
{
free(array->array);
array->array = NULL;
}
printf("Finished destroy\n");
lua_settop(L, 0);
}
else
{
if (argc != 2)
{
lua_settop(L, 0);
luaL_error(L, "Invalid arguments");
}
if (lua_tointeger(L, 2))
{
lua_pushinteger(L, array->array[lua_tointeger(L, 2)]);
}
else
{
lua_settop(L, 0);
luaL_error(L, "Bad index supplied");
}
lua_remove(L, 2);
lua_remove(L, 1);
ret = 1;
}
return ret;
}
int luaopen_TestArray(lua_State* L)
{
/* Set up metatable */
lua_newtable(L);
lua_pushliteral(L, "__index");
lua_pushcfunction(L, indexFunc);
lua_settable(L, -3);
lua_setfield(L, LUA_REGISTRYINDEX, TEST_METATABLE);
/* Set up 'static' stuff */
lua_newtable(L);
lua_pushliteral(L, "newarray");
lua_pushcfunction(L, newArray);
lua_settable(L, -3);
lua_setglobal(L, "TestArray");
return 0;
}
I compiled with:
gcc -std=c99 -Wall -fPIC -shared -o TestArray.so test.c -llua
The Lua test program is as follows:
require("TestArray")
a = TestArray.newarray()
print(a[5])
a:destroy()
The output:
$ lua test.lua
5
Finished destroy
lua: test.lua:7: attempt to call method 'destroy' (a nil value)
stack traceback:
test.lua:7: in main chunk
[C]: ?
$
So Lua does what it's supposed to by retrieving the 6th element's value (in terms of C) and printing it (as it surely does through indexFunc). Then it proceeds to execute the destroy-specific code in indexFunc, then tries to look for a function called destroy, and I have no idea why. It found the __index metamethod, so I don't understand why it looked elsewhere afterwards. Why does it do this, and what am I doing wrong?
Lua version: 5.1.4.
__index is expected to return a value. Yours doesn't.
Specifically, when you write this:
a:destroy()
That is equivalent to:
getmetatable(a).__index(a, "destroy")(a)
i.e. call the __index metamethod, then call whatever it returns passing it a as the argument.
But if we look at your __index implementation, it doesn't respect that contract:
int indexFunc(lua_State* L)
{
int argc = lua_gettop(L);
array_t* array = luaL_checkudata(L, 1, TEST_METATABLE);
const char* key = luaL_checkstring(L, 2);
int ret = 0;
if (!strcmp(key, "destroy"))
{
/* ... delete the array ... */
lua_settop(L, 0);
}
else
{
/* ... push the value ... */
}
return ret; /* since key == "destroy", ret == 0 here */
}
If the key is "destroy", it doesn't return a function; instead it destroys the array immediately and returns nothing, which is equivalent in this case to returning nil. Then the lua code tries to call the returned nil and explodes.
Instead, you need to create a separate function that does the destroy, e.g.
int destroyFunc(lua_State * L) {
array_t array = luaL_checkudata(L, 1, TEST_METATABLE);
free(array->array);
array->array = NULL;
return 0;
}
And then have your __index return that function rather than calling it:
lua_pushcfunction(L, destroyFunc);
return 1;
At which point the Lua code will be able to call that function.
Related
(Lua 5.2)
I am writing bindings from ncurses to Lua and I want to include some values other than functions. I am currently binding functions like this:
#define VERSION "0.1.0"
// Method implementation
static int example(lua_State* L){
return 0;
}
// Register library using this array
static const luaL_Reg examplelib[] = {
{"example", example},
{NULL, NULL}
}
// Piece it all together
LUALIB_API int luaopen_libexample(lua_State* L){
luaL_newlib(L, examplelib);
lua_pushstring(L, VERSION);
// Set global version string
lua_setglobal(L, "_EXAMPLE_VERSION");
return 1;
}
This yields a table with a couple functions (in this case, only one) and a global string value, but I want to put a number value in the library. So for example, right now, lib = require("libexample"); will return a table with one function, example, but I want it to also have a number, exampleNumber. How would I accomplish this?
Thank you
Just push a number in the module table.
#include <lua.h>
#include <lauxlib.h>
static char const VERSION[] = "0.1.0";
// Method implementation
static int example(lua_State* L){
return 0;
}
// Register library using this array
static const luaL_Reg examplelib[] = {
{"example", example},
{NULL, NULL}
};
// Piece it all together
LUAMOD_API int luaopen_libexample(lua_State* L){
luaL_newlib(L, examplelib);
// Set a number in the module table
lua_pushnumber(L, 1729);
lua_setfield(L, -2, "exampleNumber");
// Set global version string
lua_pushstring(L, VERSION);
lua_setglobal(L, "_EXAMPLE_VERSION");
return 1;
}
then compile with
gcc -I/usr/include/lua5.2 -shared -fPIC -o libexample.so test.c -llua5.2
and use it like
local ex = require"libexample"
print(ex.exampleNumber)
Suppose I'm working with the following C snippet:
void inc(int *num) {*num++;}
void dec(int *num) {*num--;}
void f(int var) {
inc(&var);
dec(&var);
}
By using a static analyzer, I want to be able to tell if the value of var didn't change during the function's execution. I know I have to keep its state on my own (that's the point of writing a Clang checker), but I'm having troubles getting a unique reference of this variable.
For example: if I use the following API
void MySimpleChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
SymbolRef MyArg = Call.getArgSVal(0).getAsSymbol();
}
I'd expect it to return a pointer to this symbol's representation in my checker's context. However, I always get 0 into MyArg by using it this way. This happens for both inc and dec functions in the pre and post callbacks.
What am I missing here? What concepts did I get wrong?
Note: I'm currently reading the Clang CFE Internals Manual and I've read the excellent How to Write a Checker in 24 Hours material. I still couldn't find my answer so far.
Interpretation of question
Specifically, you want to count the calls to inc and dec applied to each variable and report when they do not balance for some path in a function.
Generally, you want to know how to associate an abstract value, here a number, with a program variable, and be able to update and query that value along each execution path.
High-level answer
Whereas the tutorial checker SimpleStreamChecker.cpp associates an abstract value with the value stored in a variable, here we want associate an abstract value with the variable itself. That is what IteratorChecker.cpp does when tracking containers, so I based my solution on it.
Within the static analyzer's abstract state, each variable is represented by a MemRegion object. So the first step is to make a map where MemRegion is the key:
REGISTER_MAP_WITH_PROGRAMSTATE(TrackVarMap, MemRegion const *, int)
Next, when we have an SVal that corresponds to a pointer to a variable, we can use SVal::getAsRegion to get the corresponding MemRegion. For instance, given a CallEvent, call, with a first argument that is a pointer, we can do:
if (MemRegion const *region = call.getArgSVal(0).getAsRegion()) {
to get the region that the pointer points at.
Then, we can access our map using that region as its key:
state = state->set<TrackVarMap>(region, newValue);
Finally, in checkDeadSymbols, we use SymbolReaper::isLiveRegion to detect when a region (variable) is going out of scope:
const TrackVarMapTy &Map = state->get<TrackVarMap>();
for (auto const &I : Map) {
MemRegion const *region = I.first;
int delta = I.second;
if (SymReaper.isLiveRegion(region) || (delta==0))
continue; // Not dead, or unchanged; skip.
Complete example
To demonstrate, here is a complete checker that reports unbalanced use of inc and dec:
// TrackVarChecker.cpp
// https://stackoverflow.com/questions/23448540/how-to-keep-track-of-a-variable-with-clangs-static-analyzer
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
using namespace clang;
using namespace ento;
namespace {
class TrackVarChecker
: public Checker< check::PostCall,
check::DeadSymbols >
{
mutable IdentifierInfo *II_inc, *II_dec;
mutable std::unique_ptr<BuiltinBug> BT_modified;
public:
TrackVarChecker() : II_inc(nullptr), II_dec(nullptr) {}
void checkPostCall(CallEvent const &Call, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
};
} // end anonymous namespace
// Map from memory region corresponding to a variable (that is, the
// variable itself, not its current value) to the difference between its
// current and original value.
REGISTER_MAP_WITH_PROGRAMSTATE(TrackVarMap, MemRegion const *, int)
void TrackVarChecker::checkPostCall(CallEvent const &call, CheckerContext &C) const
{
const FunctionDecl *FD = dyn_cast<FunctionDecl>(call.getDecl());
if (!FD || FD->getKind() != Decl::Function) {
return;
}
ASTContext &Ctx = C.getASTContext();
if (!II_inc) {
II_inc = &Ctx.Idents.get("inc");
}
if (!II_dec) {
II_dec = &Ctx.Idents.get("dec");
}
if (FD->getIdentifier() == II_inc || FD->getIdentifier() == II_dec) {
// We expect the argument to be a pointer. Get the memory region
// that the pointer points at.
if (MemRegion const *region = call.getArgSVal(0).getAsRegion()) {
// Increment the associated value, creating it first if needed.
ProgramStateRef state = C.getState();
int delta = (FD->getIdentifier() == II_inc)? +1 : -1;
int const *curp = state->get<TrackVarMap>(region);
int newValue = (curp? *curp : 0) + delta;
state = state->set<TrackVarMap>(region, newValue);
C.addTransition(state);
}
}
}
void TrackVarChecker::checkDeadSymbols(
SymbolReaper &SymReaper, CheckerContext &C) const
{
ProgramStateRef state = C.getState();
const TrackVarMapTy &Map = state->get<TrackVarMap>();
for (auto const &I : Map) {
// Check for a memory region (variable) going out of scope that has
// a non-zero delta.
MemRegion const *region = I.first;
int delta = I.second;
if (SymReaper.isLiveRegion(region) || (delta==0)) {
continue; // Not dead, or unchanged; skip.
}
//llvm::errs() << region << " dead with delta " << delta << "\n";
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
if (!BT_modified) {
BT_modified.reset(
new BuiltinBug(this, "Delta not zero",
"Variable changed from its original value."));
}
C.emitReport(llvm::make_unique<BugReport>(
*BT_modified, BT_modified->getDescription(), N));
}
}
}
void ento::registerTrackVarChecker(CheckerManager &mgr) {
mgr.registerChecker<TrackVarChecker>();
}
bool ento::shouldRegisterTrackVarChecker(const LangOptions &LO) {
return true;
}
To hook this in to the rest of Clang, add entries to:
clang/include/clang/StaticAnalyzer/Checkers/Checkers.td and
clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
Example input to test it:
// trackvar.c
// Test for TrackVarChecker.
// The behavior of these functions is hardcoded in the checker.
void inc(int *num);
void dec(int *num);
void call_inc(int var) {
inc(&var);
} // reported
void call_inc_dec(int var) {
inc(&var);
dec(&var);
} // NOT reported
void if_inc(int var) {
if (var > 2) {
inc(&var);
}
} // reported
void indirect_inc(int val) {
int *p = &val;
inc(p);
} // reported
Sample run:
$ gcc -E -o trackvar.i trackvar.c
$ ~/bld/llvm-project/build/bin/clang -cc1 -analyze -analyzer-checker=alpha.core.TrackVar trackvar.i
trackvar.c:10:1: warning: Variable changed from its original value
}
^
trackvar.c:21:1: warning: Variable changed from its original value
}
^
trackvar.c:26:1: warning: Variable changed from its original value
}
^
3 warnings generated.
I think you missed the check that this call event is a call to your function inc/dec. You should have something like
void MySimpleChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
const IdentifierInfo* callee = Call.getCalleeIdentifier();
if (callee->getName().str() == "inc" || callee->getName().str() == "dec")
SymbolRef MyArg = Call.getArgSVal(0).getAsSymbol();
}
I'm trying Lua and want to know how lua_State working
code and result:
state.c
#include <stdio.h>
#include "lua/src/lua.h"
#include "lua/src/lauxlib.h"
static void stackDump(lua_State *L){
int i;
int top = lua_gettop(L);
for(i = 1; i<= top; i++) {
int t = lua_type(L, i);
switch(t){
case LUA_TSTRING:
printf("'%s'", lua_tostring(L, i));
break;
case LUA_TBOOLEAN:
printf(lua_toboolean(L, i) ?"true":"false");
break;
case LUA_TNUMBER:
printf("%g", lua_tonumber(L, i));
break;
default:
printf("%s", lua_typename(L, t));
break;
}
printf(" ");
}
printf("\n");
}
static int divide(struct lua_State *L){
double a = lua_tonumber(L, 1);
double b = lua_tonumber(L, 2);
printf("%p\n", L);
stackDump(L);
int quot = (int)a / (int)b;
int rem = (int)a % (int)b;
lua_pushnumber(L, quot);
lua_pushnumber(L, rem);
stackDump(L);
printf("---end div---\n");
return 2;
}
int main(void){
struct lua_State *L = lua_open();
lua_pushboolean(L, 1);
lua_pushnumber(L, 10);
lua_pushnil(L);
lua_pushstring(L, "hello");
printf("%p\n", L);
stackDump(L);
lua_register(L, "div", divide);
luaL_dofile(L, "div.lua");
stackDump(L);
lua_close(L);
return 0;
}
div.lua
local c = div(20, 10)
0x100c009e0
true 10 nil 'hello'
---start div---
0x100c009e0
20 10
20 10 2 0
---end div---
true 10 nil 'hello'
I see lua_State in divide is the same with the main one, but they have different data in stack, How this be done ?
I know the best way to understand this is to read source code of Lua , maybe you can tell me where to find the right place.
Think of lua_State as containing the Lua stack, as well as indices delimiting the current visible part of the stack. When you invoke a Lua function, it may look like you have a new stack, but really only the indices have changed. That's the simplified version.
lua_State is defined in lstate.h. I've pulled out the relevant parts for you. stack is the beginning of the big Lua stack containing everything. base is the beginning of the stack for the current function. This is what your function sees as "the stack" when it is executing.
struct lua_State {
/* ... */
StkId top; /* first free slot in the stack */
StkId base; /* base of current function */
/* ... */
StkId stack_last; /* last free slot in the stack */
StkId stack; /* stack base */
/* ... */
};
Programming in Lua, 2nd Edition discusses Lua states in chapter 30: Threads and States. You'll find some good information there. For example, lua_State not only represents a Lua state, but also a thread within that state. Furthermore, all threads have their own stack.
It gets different data the same way anything gets different data: code changes the data inside of the object.
struct Object
{
int val;
};
void more_stuff(Object *the_data)
{
//the_data->val has 5 in it now.
}
void do_stuff(Object *the_data)
{
int old_val = the_data->val;
the_data->val = 5;
more_stuff(the_data);
the_data->val = old_val;
}
int main()
{
Object my_data;
my_data.val = 1;
//my_data.val has 1.
do_stuff(&my_data);
//my_data.val still has 1.
}
When Lua calls a registered C function, it gives it a new stack frame.
I'm wrapping a C function with Lua, using the Lua-C API for Lua 5.2:
#include <lua.h>
#include <lauxlib.h>
#include <stdlib.h>
#include <stdio.h>
int foo_gc();
int foo_index();
int foo_newindex();
int foo_dosomething();
int foo_new();
struct foo {
int x;
};
static const luaL_Reg _meta[] = {
{"__gc", foo_gc},
{"__index", foo_index},
{"__newindex", foo_newindex},
{ NULL, NULL }
};
static const luaL_Reg _methods[] = {
{"new", foo_new},
{"dosomething", foo_dosomething},
{ NULL, NULL }
};
int foo_gc(lua_State* L) {
printf("## __gc\n");
return 0;
}
int foo_newindex(lua_State* L) {
printf("## __newindex\n");
return 0;
}
int foo_index(lua_State* L) {
printf("## __index\n");
return 0;
}
int foo_dosomething(lua_State* L) {
printf("## dosomething\n");
return 0;
}
int foo_new(lua_State* L) {
printf("## new\n");
lua_newuserdata(L,sizeof(Foo));
luaL_getmetatable(L, "Foo");
lua_setmetatable(L, -2);
return 1;
}
void register_foo_class(lua_State* L) {
luaL_newlib(L, _methods);
luaL_newmetatable(L, "Foo");
luaL_setfuncs(L, _meta, 0);
lua_setmetatable(L, -2);
lua_setglobal(L, "Foo");
}
When I run this Lua:
local foo = Foo.new()
foo:dosomething()
...I see this output (with error):
## new
## __index
Failed to run script: script.lua:2: attempt to call method 'dosomething' (a nil value)
What am I doing wrong?
Ok, got it working. I had to add __index and __metatable to Foo's new metatable, as shown below:
void register_foo_class(lua_State* L) {
int lib_id, meta_id;
/* newclass = {} */
lua_createtable(L, 0, 0);
lib_id = lua_gettop(L);
/* metatable = {} */
luaL_newmetatable(L, "Foo");
meta_id = lua_gettop(L);
luaL_setfuncs(L, _meta, 0);
/* metatable.__index = _methods */
luaL_newlib(L, _methods);
lua_setfield(L, meta_id, "__index");
/* metatable.__metatable = _meta */
luaL_newlib(L, _meta);
lua_setfield(L, meta_id, "__metatable");
/* class.__metatable = metatable */
lua_setmetatable(L, lib_id);
/* _G["Foo"] = newclass */
lua_setglobal(L, "Foo");
}
I tried replying to your solution but apparently I don't have the reputation to do so yet, so here goes a separate answer.
Your solution is pretty nice, but it does not allow for something that I'd like to do: Have both "array-like" access to an object and still have functions on it. Have a look at this Lua code:
Foo = {}
mt = {
__index = function(table, key)
print("Accessing array index ", tostring(key), "\n")
return 42
end
}
setmetatable(Foo, mt)
Foo.bar = function()
return 43
end
print(tostring(Foo[13]), "\n")
print(tostring(Foo.bar()), "\n")
--[[
Output:
Accessing array index 13
42
43
]]--
Registering a class using your solution does not seem to allow for this, as the __index entry is overwritten.
It might not make sense to have both array access and function access on a class, but for the sake of simplicity (offering one C function for registering both types of classes) I'd like to use the same code everywhere. Does anyone have an idea how this restriction could be circumvented, so that I can create a class from C which has both a function Foo.bar() but also Foo[13]?
Here's how I would satisfy both your criteria as well as j_schultz's
#include <lua.h>
#include <lauxlib.h>
#include <stdlib.h>
#include <stdio.h>
#define LUA_FOO "Foo"
typedef struct {
int x;
} Foo;
static int foo_gc(lua_State *L) {
printf("## __gc\n");
Foo *foo = *(Foo**)luaL_checkudata(L, 1, LUA_FOO);
free(foo);
return 0;
}
static int foo_doSomething(lua_State *L) {
printf("## doSomething\n");
Foo *foo = *(Foo**)luaL_checkudata(L, 1, LUA_FOO);
lua_pushinteger(L, foo->x);
return 1;
}
static int foo_new(lua_State* L) {
printf("## new\n");
Foo *foo = malloc(sizeof(Foo));
int i = 1 + lua_istable(L, 1);
foo->x = !lua_isnoneornil(L, i) ? luaL_checkinteger(L, i) : 0;
*(Foo**)lua_newuserdata(L, sizeof(Foo*)) = foo;
luaL_setmetatable(L, LUA_FOO);
return 1;
}
static int foo_index(lua_State *L) {
printf("## index\n");
int i = luaL_checkinteger(L, 2);
lua_pushinteger(L, i);
return 1;
}
int luaopen_foo(lua_State *L) {
// instance functions
static const luaL_Reg meta[] =
{ { "__gc" ,foo_gc },
{ NULL ,NULL } };
static const luaL_Reg meth[] =
{ { "doSomething" ,foo_doSomething },
{ NULL ,NULL } };
luaL_newmetatable(L, LUA_FOO);
luaL_setfuncs (L, meta, 0);
luaL_newlib (L, meth);
lua_setfield (L, -2, "__index");
lua_pop (L, 1);
// static functions
static const luaL_Reg static_meta[] =
{ { "__index" ,foo_index },
{ "__call" ,foo_new },
{ NULL ,NULL } };
static const luaL_Reg static_meth[] =
{ { "new" ,foo_new },
{ NULL ,NULL } };
luaL_newlib (L, static_meth);
luaL_newlib (L, static_meta);
lua_setmetatable (L, -2);
return 1;
}
Lua code:
local Foo = require('foo')
local foo = Foo.new(12)
local bar = Foo(24)
print(Foo[13])
print(foo:doSomething())
print(bar:doSomething())
Lua output:
## new
## new
## index
13
## doSomething
12
## doSomething
24
## __gc
## __gc
Usually one would only push 'userdata' when the data isn't any of Lua's standard types (number, string, bool, etc).
But how would you push an actually Function pointer to Lua (not as userdata; since userdata is not executable as function in Lua), assuming the function looks like so:
void nothing(const char* stuff)
{
do_magic_things_with(stuff);
}
The returned value should behave like the returned value from this native Lua function:
function things()
return function(stuff)
do_magic_things_with(stuff)
end
end
Is this possible to do with the C API? If yes, how (Examples would be appreciated)?
EDIT: To add some clarity, The value is supposed to be returned by a function exposed to Lua through the C API.
Use lua_pushcfunction
Examples are included in PiL
Here is an example that follows the form of the currently accepted answer.
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <stdio.h>
/* this is the C function you want to return */
static void
cfunction(const char *s)
{
puts(s);
}
/* this is the proxy function that acts like cfunction */
static int
proxy(lua_State *L)
{
cfunction(luaL_checkstring(L, 1));
return 0;
}
/* this global function returns "cfunction" to Lua. */
static int
getproxy(lua_State *L)
{
lua_pushcfunction(L, &proxy);
return 1;
}
int
main(int argc, char **argv)
{
lua_State *L;
L = luaL_newstate();
/* set the global function that returns the proxy */
lua_pushcfunction(L, getproxy);
lua_setglobal(L, "getproxy");
/* see if it works */
luaL_dostring(L, "p = getproxy() p('Hello, world!')");
lua_close(L);
return 0;
}
You could return a userdata with a metatable that proxies your C function through the __call metamethod. That way the userdata could be called like a function. Below is a full program example.
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <stdio.h>
/* this is the C function you want to return */
static void
cfunction(const char *s)
{
puts(s);
}
/* this is the proxy function that will be used as the __call metamethod */
static int
proxy(lua_State *L)
{
luaL_checkudata(L, 1, "proxy");
cfunction(luaL_checkstring(L, 2));
return 0;
}
/* this global function returns the C function with a userdata proxy */
static int
getproxy(lua_State *L)
{
lua_newuserdata(L, sizeof (int));
luaL_getmetatable(L, "proxy");
lua_setmetatable(L, -2);
return 1;
}
int
main(int argc, char **argv)
{
lua_State *L;
L = luaL_newstate();
/* create the proxy metatable */
luaL_newmetatable(L, "proxy");
lua_pushcfunction(L, proxy);
lua_setfield(L, -2, "__call");
/* set the global function that returns the proxy */
lua_pushcfunction(L, getproxy);
lua_setglobal(L, "getproxy");
/* see if it works */
luaL_dostring(L, "p = getproxy() p('Hello, world!')");
lua_close(L);
return 0;
}
In retrospect, I completely over-thought what you are asking. All you really need to do is to create a function of type lua_CFunction that pulls the parameters from the Lua stack and passes them on to the target C function. The code above answers your question literally, but it is probably overkill for what you really need to accomplish.