Callbacks in Lua wrapper of mplib
Hi, I recently discovered that the Lua wrapper of mplib registers all callbacks globally such that creating multiple mplib instances with different callbacks breaks. This affects the undocumented `run_script` and `make_text` callbacks, but also the documented `find_file`: For example the plain LuaTeX document \directlua{ local mp = mplib.new{ find_file = function(name, mode, type) return name end } do % Create a temporary second instance with a different run_script handler mplib.new{ find_file = function(name, mode, type) if name == 'cmr10' then print'This should not happen' end return name end }:finish() end % Now trigger find_file using the *first* mp instance which should *not* trigger a message mp:execute[[ input cmr10; ]] } \bye shows the message 'This should not happen', because the find_file implementation of the second call to `mplib.new` is also used for the first `mp` instance. This can be fixed by storing the callbacks in userdata associated with the mp uservalue instead of in the global registry: diff --git a/source/texk/web2c/mplibdir/lmplib.c b/source/texk/web2c/mplibdir/lmplib.c index eb8432bb5..88873ed66 100644 --- a/source/texk/web2c/mplibdir/lmplib.c +++ b/source/texk/web2c/mplibdir/lmplib.c @@ -329,7 +329,9 @@ static char *mplib_find_file(MP mp, const char *fname, const char *fmode, int ft { lua_State *L = (lua_State *)mp_userdata(mp); lua_checkstack(L, 4); - lua_getfield(L, LUA_REGISTRYINDEX, "mplib.file_finder"); + lua_getuservalue(L, 1); + lua_getfield(L, -1, "file_finder"); + lua_replace(L, -2); if (lua_isfunction(L, -1)) { char *s = NULL; const char *x = NULL; @@ -365,9 +367,9 @@ static int mplib_find_file_function(lua_State * L) /*tex An error. */ return 1; } - lua_pushstring(L, "mplib.file_finder"); + lua_pushstring(L, "file_finder"); lua_pushvalue(L, -2); - lua_rawset(L, LUA_REGISTRYINDEX); + lua_rawset(L, -4); return 0; } @@ -379,8 +381,10 @@ static void mplib_warning(const char *str) static void mplib_script_error(MP mp, const char *str) { lua_State *L = (lua_State *)mp_userdata(mp); - lua_checkstack(L, 1); - lua_getfield(L, LUA_REGISTRYINDEX, "mplib.script_error"); + lua_checkstack(L, 2); + lua_getuservalue(L, 1); + lua_getfield(L, -1, "script_error"); + lua_replace(L, -2); if (lua_isfunction(L, -1)) { lua_pushstring(L, str); /*tex We assume that the function is okay. */ @@ -397,17 +401,19 @@ static int mplib_script_error_function(lua_State * L) /*tex An error. */ return 1; } - lua_pushstring(L, "mplib.script_error"); + lua_pushstring(L, "script_error"); lua_pushvalue(L, -2); - lua_rawset(L, LUA_REGISTRYINDEX); + lua_rawset(L, -4); return 0; } static char *mplib_run_script(MP mp, const char *str) { lua_State *L = (lua_State *)mp_userdata(mp); - lua_checkstack(L, 1); - lua_getfield(L, LUA_REGISTRYINDEX, "mplib.run_script"); + lua_checkstack(L, 2); + lua_getuservalue(L, 1); + lua_getfield(L, -1, "run_script"); + lua_replace(L, -2); if (lua_isfunction(L, -1)) { char *s = NULL; const char *x = NULL; @@ -433,17 +439,19 @@ static int mplib_run_script_function(lua_State * L) if (!(lua_isfunction(L, -1) || lua_isnil(L, -1))) { return 1; /* error */ } - lua_pushstring(L, "mplib.run_script"); + lua_pushstring(L, "run_script"); lua_pushvalue(L, -2); - lua_rawset(L, LUA_REGISTRYINDEX); + lua_rawset(L, -4); return 0; } static char *mplib_make_text(MP mp, const char *str, int mode) { lua_State *L = (lua_State *)mp_userdata(mp); - lua_checkstack(L, 1); - lua_getfield(L, LUA_REGISTRYINDEX, "mplib.make_text"); + lua_checkstack(L, 2); + lua_getuservalue(L, 1); + lua_getfield(L, -1, "make_text"); + lua_replace(L, -2); if (lua_isfunction(L, -1)) { char *s = NULL; const char *x = NULL; @@ -471,9 +479,9 @@ static int mplib_make_text_function(lua_State * L) /*tex An error. */ return 1; } - lua_pushstring(L, "mplib.make_text"); + lua_pushstring(L, "make_text"); lua_pushvalue(L, -2); - lua_rawset(L, LUA_REGISTRYINDEX); + lua_rawset(L, -4); return 0; } @@ -544,6 +552,8 @@ static int mplib_new(lua_State * L) /* options->script_error = mplib_script_error; */ options->print_found_names = 1; options->ini_version = 1; + /*tex Here we create the uservalue table for the callbacks: */ + lua_newtable(L); if (lua_type(L, 1) == LUA_TTABLE) { for (i = 0; mplib_parms[i].name != NULL; i++) { lua_getfield(L, 1, mplib_parms[i].name); @@ -606,6 +616,7 @@ static int mplib_new(lua_State * L) lua_pop(L, 1); } } + lua_setuservalue(L, -2); *mp_ptr = mp_initialize(options); xfree(options->command_line); xfree(options->mem_name);
On Wed, Nov 7, 2018 at 12:18 PM Marcel Krüger
Hi,
I recently discovered that the Lua wrapper of mplib registers all callbacks globally such that creating multiple mplib instances with different callbacks breaks.
why not this ? \directlua{ local current_instance local custom_find_file = custom_find_file or {} local mp_find_file_driver = function(name, mode, type) print("I am ",current_instance) if custom_find_file[current_instance] then return custom_find_file[current_instance](name, mode, type) else return "unregistered" end end custom_find_file['mp1'] = function(name, mode, type) return name end custom_find_file['mp2'] = function(name, mode, type) if name == 'cmr10' then print'This should not happen' end return name end local mp1 = mplib.new{ find_file = mp_find_file_driver } local mp2 = mplib.new{ find_file = mp_find_file_driver } current_instance = "mp1" mp1:execute[[ input cmr10; ]] current_instance = "mp2" mp2:execute[[ input cmr10; ]] } \bye -- luigi
participants (2)
-
luigi scarso
-
Marcel Krüger