1
votes

I have an application that uses lua files for some of its more obscure configuration options. As such it mostly contains calls into the app to create things and alter properties; most C functions don't have a return value but some do.

I now have a need to read these same configuration files into a different application, and perform significantly different things when the functions are called (so I can't use common code). In addition, I'm only interested in a subset of the possible functions, and I think I can get away with by default ignoring (and/or returning nil) any other function call.

So I'm wondering what the best approach is here. How (from a C++ app), can I load and execute a lua script such that expressions etc are evaluated as normal but I can intercept and process certain app-defined C functions while simply ignoring (returning nil if required) calls to any other C functions?

(Note: I do have access to the vocabulary of the original app, which mostly uses luabind; I could just use the same definitions and change the implementation, but that's too fragile since the original app can have more functions added to it later. I would like something more generic.)


The goal is to get a bit of C code which I can use as a generic placeholder; the end result being "anything that's defined (standard library routines, functions defined in Lua, and C functions explicitly registered), call it as normal; for anything else, call one specific routine that simply does nothing, instead of raising an error". And preferably something compatible with luabind.

The whole process is initiated by a bit of C code that sets up the Lua environment, loads a set of files, calls one function, and then destroys the environment. There won't be anything ongoing.

3

3 Answers

4
votes

Set a __call metamethod for nil:

debug.setmetatable(nil, { __call=function () end })

The _index metamethod for _G or other tables does not work because the name is resolved before the call.

(You don't need to use the debug API or library if you're setting this from C.)

3
votes

How about using setfenv and a metatable? You can replace global environment table of certain function with an empty table. And then, set the placeholder function to ignore C-defined function.

local env = {}  -- empty environment
local metatbl = {}
function metatbl.__index (tbl, key)  -- provides placeholder function
    return function()
        print(key .. " called")
        return(nil)
    end
end

setmetatable(env, metatbl)

function samplefunc()  -- your Lua code goes here
    globalfunction "xyz"   -- calls placeholder function
end

setfenv(samplefunc, env)
samplefunc()

If you want to use build-in function such as print, you can push it into env talbe like:

local env = {print = print}
0
votes

If you have some way of differentiating the C functions from the ordinary Lua functions in your script, you can iterate over all functions defined in your Lua system, and for each C function that isn't on the list of functions you care about, replace that function's implementation with a simple nil-returning one. This is really easy if all the c-binding functions are defined tidily together in a table; if they're in _G you have a bit of a job ahead of you. The functions you do care about get bound via luabind as normal.