Overriding the default 'require' in libLua (offer)

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Overriding the default 'require' in libLua (offer)

Paul Bergen
We have our own application, written in C, that allows users to embed
snippets of Lua which our C program then executes at various times.
Rather than writing all the Lua code directly inline, our users want
to be able to have common modules with shared code that they can
include with a 'require'.  If they put this shared code in a file,
like mycode.lua, and put the file in the same folder as our C program,
it works fine.  However, we have our own user interface and don't want
to put these stray files in our program directory.  Rather, we will
compress them and bundle them in our own data files.

So this means the 'require' in Lua will error out and won't find the
file.  So when we create the Lua state in our C app, we want to
override the built-in 'require' to instead point to our own C
function.  In our C function, it should be identical to the stock Lua
require, except that if the fopen() command fails, we want to have our
own code which retrieves the contents of the files ourself, from our
own data store. We won't be parsing the contents or doing anything
with them.  Just putting them in a (char *) buffer and handing it back
to the stock Lua require function to process the same as if it had
opened the file itself with fopen().

Anybody know how to do this?  And if anybody cares to write the C code
to do this, I'll be happy to paypal/wire some money for it.  I'm not
too familiar with libLua and under time pressure.

Reply | Threaded
Open this post in threaded view
|

Re: Overriding the default 'require' in libLua (offer)

Peter Cawley
On Wed, Jan 4, 2012 at 5:36 PM, Paul Bergen <[hidden email]> wrote:

> We have our own application, written in C, that allows users to embed
> snippets of Lua which our C program then executes at various times.
> Rather than writing all the Lua code directly inline, our users want
> to be able to have common modules with shared code that they can
> include with a 'require'.  If they put this shared code in a file,
> like mycode.lua, and put the file in the same folder as our C program,
> it works fine.  However, we have our own user interface and don't want
> to put these stray files in our program directory.  Rather, we will
> compress them and bundle them in our own data files.
>
> So this means the 'require' in Lua will error out and won't find the
> file.  So when we create the Lua state in our C app, we want to
> override the built-in 'require' to instead point to our own C
> function.  In our C function, it should be identical to the stock Lua
> require, except that if the fopen() command fails, we want to have our
> own code which retrieves the contents of the files ourself, from our
> own data store. We won't be parsing the contents or doing anything
> with them.  Just putting them in a (char *) buffer and handing it back
> to the stock Lua require function to process the same as if it had
> opened the file itself with fopen().
>
> Anybody know how to do this?  And if anybody cares to write the C code
> to do this, I'll be happy to paypal/wire some money for it.  I'm not
> too familiar with libLua and under time pressure.

I am assuming a C function called GetContents. It receives as a
parameter the string passed to require(), and it either returns NULL
or returns a pointer to the file contents and stores the file size in
the given parameter.

const char* GetContents(const char* name, size_t* size_out);

This can then be adapted in a pattern similar to loader_Lua from Lua's
loadlib.c:

static int loader_Custom(lua_State *L) {
  size_t size;
  const char *name = luaL_checkstring(L, 1);
  const char *content = GetContents(name, &size);
  if(content) {
    lua_pushfstring("@%s", name);
    if(luaL_loadbuffer(L, content, size, lua_tostring(L, -1)) != 0)
      luaL_error(L, "error loading module " LUA_QS ":\n\t%s", name,
lua_tostring(L, -1));
  } else {
    lua_pushfstring("\n\tno file " LUA_QS, name);
  }
  return 1;
}

This function can then be linked into require()'s pipeline by
executing the following code (after the base libraries have been
initialised on L):

luaL_loadstring(L, "table.insert(package.loaders, 3, ...)");
lua_pushcfunction(L, loader_Custom);
lua_call(L, 1, 0);

That was very quickly thrown together from memory, and not tested, so
it might not even compile.

Reply | Threaded
Open this post in threaded view
|

Re: Overriding the default 'require' in libLua (offer)

Reuben Thomas-5
There's no obvious reason to patch require in C; why not patch it in
Lua? Write your own require which calls the original require, and, if
it fails, does its own thing, loading a built-in string or whatever:

local old_require = require
function require (module)
  local ok, m = pcall (old_require, module)
  if ok then return m end
  ... -- try getting module from internal strings
end

Reply | Threaded
Open this post in threaded view
|

Re: Overriding the default 'require' in libLua (offer)

Sean Conner
In reply to this post by Paul Bergen
It was thus said that the Great Paul Bergen once stated:

> We have our own application, written in C, that allows users to embed
> snippets of Lua which our C program then executes at various times.
> Rather than writing all the Lua code directly inline, our users want
> to be able to have common modules with shared code that they can
> include with a 'require'.  If they put this shared code in a file,
> like mycode.lua, and put the file in the same folder as our C program,
> it works fine.  However, we have our own user interface and don't want
> to put these stray files in our program directory.  Rather, we will
> compress them and bundle them in our own data files.
>
> So this means the 'require' in Lua will error out and won't find the
> file.  So when we create the Lua state in our C app, we want to
> override the built-in 'require' to instead point to our own C
> function.  In our C function, it should be identical to the stock Lua
> require, except that if the fopen() command fails, we want to have our
> own code which retrieves the contents of the files ourself, from our
> own data store. We won't be parsing the contents or doing anything
> with them.  Just putting them in a (char *) buffer and handing it back
> to the stock Lua require function to process the same as if it had
> opened the file itself with fopen().
>
> Anybody know how to do this?  And if anybody cares to write the C code
> to do this, I'll be happy to paypal/wire some money for it.  I'm not
> too familiar with libLua and under time pressure.

  The easiest way appears to be to add a custom loader to the
package.loaders array.  The function just takes a string, the name of the
module to load, and it returns a function that will load the appropriate
module (if I'm reading the documentation right).  

  For anyone that might be interested in writing the code, which version of
Lua, and for what platform?

  -spc