Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lua 'require' but files are only in memory

Tags:

lua

Setting: I'm using Lua from a C/C++ environment.

I have several lua files on disk. Those are read into memory and some more memory-only lua files become available during runtime. Think e.g. of an editor, with additional unsaved lua files.

So, I have a list<identifier, lua_file_content> in memory. Some of these files have require statements in them. When I try to load all these files to a lua instance (currently via lua_dostring) I get attempt to call global require (a nil value).

Is there a possibility to provide a require function, which replaces the old one and just uses the provided in memory files (those files are on the C side)?

Is there another way of allowing require in these files without having the required files on disk?

An example would be to load the lua stdlib from memory only without altering it. (This is actually my test case.)

like image 869
Mike M Avatar asked Sep 23 '13 17:09

Mike M


3 Answers

Instead of replacing require, why not add a function to package.loaders? The code is nearly the same.

int my_loader(lua_State* state) {
    // get the module name
    const char* name = lua_tostring(state);
    // find if you have such module loaded
    if (mymodules.find(name) != mymodules.end())
    {
        luaL_loadbuffer(state, buffer, size, name);
        // the chunk is now at the top of the stack
        return 1;
    }

    // didn't find anything
    return 0;
}

// When you load the lua state, insert this into package.loaders

http://www.lua.org/manual/5.1/manual.html#pdf-package.loaders

like image 131
Colonel Thirty Two Avatar answered Nov 15 '22 17:11

Colonel Thirty Two


A pretty straightforward C++ function that would mimic require could be: (pseudocode)

int my_require(lua_State* state) {
    // get the module name
    const char* name = lua_tostring(state);
    // find if you have such module loaded
    if (mymodules.find(name) != mymodules.end())
        luaL_loadbuffer(state, buffer, size, name);
    // the chunk is now at the top of the stack
    lua_call(state)
    return 1;
}

Expose this function to Lua as require and you're good to go.

I'd also like to add that to completely mimic require's behaviour, you'd probably need to take care of package.loaded, to avoid the code to be loaded twice.

like image 35
Bartek Banachewicz Avatar answered Nov 15 '22 17:11

Bartek Banachewicz


There is no package.loaders in lua 5.2
It called package.searchers now.

#include <stdio.h>
#include <string>
#include <lua.hpp>

std::string    module_script;


int MyLoader(lua_State *L)
{
    const char *name = luaL_checkstring(L, 1);  // Module name

//  std::string    result = SearchScript(name); // Search your database.
    std::string    result = module_script;      // Just for demo.

    if( luaL_loadbuffer(L, result.c_str(), result.size(), name) )
    {
        printf("%s", lua_tostring(L, -1));
        lua_pop(L, 1);
    }

    return 1;
}

void SetLoader(lua_State* L)
{
    lua_register(L, "my_loader", MyLoader);

    std::string     str;

//  str += "table.insert(package.loaders,   2, my_loader) \n";   // Older than lua v5.2
    str += "table.insert(package.searchers, 2, my_loader) \n";

    luaL_dostring(L, str.c_str());
}

void SetModule()
{
    std::string     str;

    str += "print([[It is add.lua]]) \n";
    str += "return { func = function() print([[message from add.lua]]) end } \n";

    module_script=str;
}

void LoadMainScript(lua_State* L)
{
    std::string     str;

    str += "dev = require [[add]] \n";
    str += "print([[It is main.lua]]) \n";
    str += "dev.func() \n";

    if ( luaL_loadbuffer(L, str.c_str(), str.size(), "main") )
    {
        printf("%s", lua_tostring(L, -1));
        lua_pop(L, 1);
        return;
    }
}

int main()
{
    lua_State*  L = luaL_newstate();

    luaL_openlibs(L);

    SetModule(L);       // Write down module in memory. Lua not load it yet.
    SetLoader(L);
    LoadMainScript(L);

    lua_pcall(L,0,0,0);
    lua_close(L);

    return 0;
}
like image 37
ToyAuthor X Avatar answered Nov 15 '22 16:11

ToyAuthor X