diff options
Diffstat (limited to 'loadlib.c')
-rw-r--r-- | loadlib.c | 74 |
1 files changed, 41 insertions, 33 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: loadlib.c,v 1.107 2011/11/30 12:58:57 roberto Exp roberto $ | 2 | ** $Id: loadlib.c,v 1.108 2011/12/12 16:34:03 roberto Exp roberto $ |
3 | ** Dynamic library loader for Lua | 3 | ** Dynamic library loader for Lua |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | ** | 5 | ** |
@@ -92,9 +92,9 @@ | |||
92 | #define LUA_OFSEP "_" | 92 | #define LUA_OFSEP "_" |
93 | 93 | ||
94 | 94 | ||
95 | #define LIBPREFIX "LOADLIB: " | 95 | /* table (in the registry) that keeps handles for all loaded C libraries */ |
96 | #define CLIBS "_CLIBS" | ||
96 | 97 | ||
97 | #define POF LUA_POF | ||
98 | #define LIB_FAIL "open" | 98 | #define LIB_FAIL "open" |
99 | 99 | ||
100 | 100 | ||
@@ -248,48 +248,54 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { | |||
248 | #endif | 248 | #endif |
249 | 249 | ||
250 | 250 | ||
251 | 251 | static void *ll_checkclib (lua_State *L, const char *path) { | |
252 | static void **ll_register (lua_State *L, const char *path) { | 252 | void *plib; |
253 | void **plib; | 253 | lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); |
254 | lua_pushfstring(L, "%s%s", LIBPREFIX, path); | 254 | lua_getfield(L, -1, path); |
255 | lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ | 255 | plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ |
256 | if (!lua_isnil(L, -1)) /* is there an entry? */ | 256 | lua_pop(L, 2); /* pop CLIBS table and 'plib' */ |
257 | plib = (void **)lua_touserdata(L, -1); | ||
258 | else { /* no entry yet; create one */ | ||
259 | lua_pop(L, 1); /* remove result from gettable */ | ||
260 | plib = (void **)lua_newuserdata(L, sizeof(const void *)); | ||
261 | *plib = NULL; | ||
262 | luaL_setmetatable(L, "_LOADLIB"); | ||
263 | lua_pushfstring(L, "%s%s", LIBPREFIX, path); | ||
264 | lua_pushvalue(L, -2); | ||
265 | lua_settable(L, LUA_REGISTRYINDEX); | ||
266 | } | ||
267 | return plib; | 257 | return plib; |
268 | } | 258 | } |
269 | 259 | ||
270 | 260 | ||
261 | static void ll_addtoclib (lua_State *L, const char *path, void *plib) { | ||
262 | lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); | ||
263 | lua_pushlightuserdata(L, plib); | ||
264 | lua_pushvalue(L, -1); | ||
265 | lua_setfield(L, -3, path); /* CLIBS[path] = plib */ | ||
266 | lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ | ||
267 | lua_pop(L, 1); /* pop CLIBS table */ | ||
268 | } | ||
269 | |||
270 | |||
271 | /* | 271 | /* |
272 | ** __gc tag method: calls library's `ll_unloadlib' function with the lib | 272 | ** __gc tag method for CLIBS table: calls 'll_unloadlib' for all lib |
273 | ** handle | 273 | ** handles in list CLIBS |
274 | */ | 274 | */ |
275 | static int gctm (lua_State *L) { | 275 | static int gctm (lua_State *L) { |
276 | void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); | 276 | int n = luaL_len(L, 1); |
277 | if (*lib) ll_unloadlib(*lib); | 277 | for (; n >= 1; n--) { /* for each handle, in reverse order */ |
278 | *lib = NULL; /* mark library as closed */ | 278 | lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ |
279 | ll_unloadlib(lua_touserdata(L, -1)); | ||
280 | lua_pop(L, 1); /* pop handle */ | ||
281 | } | ||
279 | return 0; | 282 | return 0; |
280 | } | 283 | } |
281 | 284 | ||
282 | 285 | ||
283 | static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { | 286 | static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { |
284 | void **reg = ll_register(L, path); | 287 | void *reg = ll_checkclib(L, path); /* check loaded C libraries */ |
285 | if (*reg == NULL) *reg = ll_load(L, path, *sym == '*'); | 288 | if (reg == NULL) { /* must load library? */ |
286 | if (*reg == NULL) return ERRLIB; /* unable to load library */ | 289 | reg = ll_load(L, path, *sym == '*'); |
290 | if (reg == NULL) return ERRLIB; /* unable to load library */ | ||
291 | ll_addtoclib(L, path, reg); | ||
292 | } | ||
287 | if (*sym == '*') { /* loading only library (no function)? */ | 293 | if (*sym == '*') { /* loading only library (no function)? */ |
288 | lua_pushboolean(L, 1); /* return 'true' */ | 294 | lua_pushboolean(L, 1); /* return 'true' */ |
289 | return 0; /* no errors */ | 295 | return 0; /* no errors */ |
290 | } | 296 | } |
291 | else { | 297 | else { |
292 | lua_CFunction f = ll_sym(L, *reg, sym); | 298 | lua_CFunction f = ll_sym(L, reg, sym); |
293 | if (f == NULL) | 299 | if (f == NULL) |
294 | return ERRFUNC; /* unable to find function */ | 300 | return ERRFUNC; /* unable to find function */ |
295 | lua_pushcfunction(L, f); /* else create new function */ | 301 | lua_pushcfunction(L, f); /* else create new function */ |
@@ -418,12 +424,12 @@ static int loadfunc (lua_State *L, const char *filename, const char *modname) { | |||
418 | if (mark) { | 424 | if (mark) { |
419 | int stat; | 425 | int stat; |
420 | funcname = lua_pushlstring(L, modname, mark - modname); | 426 | funcname = lua_pushlstring(L, modname, mark - modname); |
421 | funcname = lua_pushfstring(L, POF"%s", funcname); | 427 | funcname = lua_pushfstring(L, LUA_POF"%s", funcname); |
422 | stat = ll_loadfunc(L, filename, funcname); | 428 | stat = ll_loadfunc(L, filename, funcname); |
423 | if (stat != ERRFUNC) return stat; | 429 | if (stat != ERRFUNC) return stat; |
424 | modname = mark + 1; /* else go ahead and try old-style name */ | 430 | modname = mark + 1; /* else go ahead and try old-style name */ |
425 | } | 431 | } |
426 | funcname = lua_pushfstring(L, POF"%s", modname); | 432 | funcname = lua_pushfstring(L, LUA_POF"%s", modname); |
427 | return ll_loadfunc(L, filename, funcname); | 433 | return ll_loadfunc(L, filename, funcname); |
428 | } | 434 | } |
429 | 435 | ||
@@ -672,10 +678,12 @@ static const lua_CFunction searchers[] = | |||
672 | 678 | ||
673 | LUAMOD_API int luaopen_package (lua_State *L) { | 679 | LUAMOD_API int luaopen_package (lua_State *L) { |
674 | int i; | 680 | int i; |
675 | /* create new type _LOADLIB */ | 681 | /* create table CLIBS to keep track of loaded C libraries */ |
676 | luaL_newmetatable(L, "_LOADLIB"); | 682 | luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); |
683 | lua_createtable(L, 0, 1); /* metatable for CLIBS */ | ||
677 | lua_pushcfunction(L, gctm); | 684 | lua_pushcfunction(L, gctm); |
678 | lua_setfield(L, -2, "__gc"); | 685 | lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ |
686 | lua_setmetatable(L, -2); | ||
679 | /* create `package' table */ | 687 | /* create `package' table */ |
680 | luaL_newlib(L, pk_funcs); | 688 | luaL_newlib(L, pk_funcs); |
681 | /* create 'searchers' table */ | 689 | /* create 'searchers' table */ |