Index: loadlib.c =================================================================== --- loadlib.c (revision 2) +++ loadlib.c (working copy) @@ -293,8 +293,10 @@ */ -static const char *loadLua (lua_State *L, const char *fname, const char *name) { +static int loadLua (lua_State *L) { const char *path; + const char *name = luaL_checkstring(L, 1); + const char *fname = luaL_gsub(L, name, ".", LUA_DIRSEP); /* try first `LUA_PATH' for compatibility */ lua_getglobal(L, "LUA_PATH"); path = lua_tostring(L, -1); @@ -306,30 +308,48 @@ if (path == NULL) luaL_error(L, "`package.path' must be a string"); fname = luaL_searchpath(L, fname, path); - if (fname == NULL) return path; /* library not found in this path */ + if (fname == NULL) return 0; /* library not found in this path */ if (luaL_loadfile(L, fname) != 0) luaL_error(L, "error loading package `%s' (%s)", name, lua_tostring(L, -1)); - return NULL; /* library loaded successfully */ + return 1; /* library loaded successfully */ } -static const char *loadC (lua_State *L, const char *fname, const char *name) { +static int loadC (lua_State *L) { const char *path; const char *funcname; + const char *name = luaL_checkstring(L, 1); + const char *fname = luaL_gsub(L, name, ".", LUA_DIRSEP); luaL_getfield(L, LUA_GLOBALSINDEX, "package.cpath"); path = lua_tostring(L, -1); if (path == NULL) luaL_error(L, "`package.cpath' must be a string"); fname = luaL_searchpath(L, fname, path); - if (fname == NULL) return path; /* library not found in this path */ + if (fname == NULL) return 0; /* library not found in this path */ funcname = luaL_gsub(L, name, ".", LUA_OFSEP); funcname = lua_pushfstring(L, "%s%s", POF, funcname); if (ll_loadfunc(L, fname, funcname) != 1) luaL_error(L, "error loading package `%s' (%s)", name, lua_tostring(L, -2)); - return NULL; /* library loaded successfully */ + return 1; /* library loaded successfully */ } +static int ll_register_loader (lua_State *L) { + int i; + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADERS"); + /* find next slot available */ + lua_rawgeti(L, -1, 0); + i = lua_tonumber(L, -1); + lua_pop(L, 1); + + /* save loader */ + lua_pushvalue(L, 1); + lua_rawseti(L, -2, i); + + return 0; +} + static int ll_require (lua_State *L) { const char *name = luaL_checkstring(L, 1); lua_settop(L, 1); @@ -344,17 +364,20 @@ lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); lua_getfield(L, -1, name); if (lua_isnil(L, -1)) { /* no preload function for that module? */ - const char *fname = luaL_gsub(L, name, ".", LUA_DIRSEP); - const char *cpath = loadC(L, fname, name); /* try a C module */ - if (cpath) { /* not found? */ - const char *path = loadLua(L, fname, name); /* try a Lua module */ - if (path) { /* yet not found? */ - lua_pushnil(L); - lua_setfield(L, 2, name); /* unmark _LOADED[name] */ - return luaL_error(L, "package `%s' not found\n" - " cpath: %s\n path: %s", - name, cpath, path); - } + /* traverse binary loader table */ + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADERS"); + int i; + for (i = 1;; ++i) { + lua_rawgeti(L, -1, i); + if (lua_isnil(L, -1)) /* no more loaders? */ + luaL_error(L, "package `%s' not found", name); + + lua_pushvalue(L, 1); /* push module name */ + lua_call(L, 1, 1); /* call loader */ + if (!lua_isnil(L, -1)) /* loaded successfully? */ + break; /* loaded: stop searching */ + + lua_pop(L, 1); /* remove nil value */ } } lua_pushvalue(L, 1); /* pass name as argument to module */ @@ -457,6 +480,24 @@ /* set field `preload' */ lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); lua_setfield(L, -2, "preload"); + + /* set field `loaders' */ + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADERS"); + lua_setfield(L, -2, "loaders"); + /* loader registration funtion */ + lua_pushcfunction(L, ll_register_loader); + lua_setfield(L, -2, "register_loader"); + + /* register predefined loaders */ + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADERS"); + lua_pushcfunction(L, loadLua); + lua_rawseti(L, -2, 1); + lua_pushcfunction(L, loadC); + lua_rawseti(L, -2, 2); + lua_pushnumber(L, 2); /* set next position to use */ + lua_rawseti(L, -2, 0); + lua_pop(L, 1); + lua_pushvalue(L, LUA_GLOBALSINDEX); luaL_openlib(L, NULL, ll_funcs, 0); /* open lib into global table */ return 1; Index: lbaselib.c =================================================================== --- lbaselib.c (revision 2) +++ lbaselib.c (working copy) @@ -561,7 +561,7 @@ lua_pushliteral(L, "dead"); else lua_pushliteral(L, "suspended"); /* initial state */ - break; + break; } default: /* some error occured */ lua_pushliteral(L, "dead"); @@ -620,6 +620,9 @@ /* create register._LOADED to track loaded modules */ lua_newtable(L); lua_setfield(L, LUA_REGISTRYINDEX, "_LOADED"); + /* create register._LOADERS to allow modules loaders to be registered */ + lua_newtable(L); + lua_setfield(L, LUA_REGISTRYINDEX, "_LOADERS"); /* create register._PRELOAD to allow pre-loaded modules */ lua_newtable(L); lua_setfield(L, LUA_REGISTRYINDEX, "_PRELOAD");