From e82bdb24f3727fbecb3d0596c1a8abc0af4cc687 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Mon, 1 Aug 2005 01:21:17 -0300 Subject: [PATCH] new loader for "all-in-one" C packages --- loadlib.c | 154 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 89 insertions(+), 65 deletions(-) diff --git a/loadlib.c b/loadlib.c index 0001abb2..063f8546 100644 --- a/loadlib.c +++ b/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.33 2005/07/12 21:17:46 roberto Exp roberto $ +** $Id: loadlib.c,v 1.34 2005/07/13 19:02:42 roberto Exp roberto $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -38,6 +38,10 @@ #define LIB_FAIL "open" +/* error codes for ll_loadfunc */ +#define ERRLIB 1 +#define ERRFUNC 2 + #define setprogdir(L) ((void)0) @@ -294,43 +298,45 @@ static int gctm (lua_State *L) { static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { - const char *reason; void **reg = ll_register(L, path); if (*reg == NULL) *reg = ll_load(L, path); if (*reg == NULL) - reason = LIB_FAIL; + return ERRLIB; /* unable to load library */ else { lua_CFunction f = ll_sym(L, *reg, sym); - if (f) { - lua_pushcfunction(L, f); - return 1; /* return function */ - } - reason = "init"; + if (f == NULL) + return ERRFUNC; /* unable to find function */ + lua_pushcfunction(L, f); + return 0; /* return function */ } - lua_pushnil(L); - lua_insert(L, -2); - lua_pushstring(L, reason); - return 3; /* return nil, ll_error, reason */ } static int ll_loadlib (lua_State *L) { const char *path = luaL_checkstring(L, 1); const char *init = luaL_checkstring(L, 2); - return ll_loadfunc(L, path, init); + int stat = ll_loadfunc(L, path, init); + if (stat == 0) /* no errors? */ + return 1; /* return the loaded function */ + else { /* error; error message is on stack top */ + lua_pushnil(L); + lua_insert(L, -2); + lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); + return 3; /* return nil, error message, and where */ + } } /* ** {====================================================== -** `require' and `module' functions +** 'require' function ** ======================================================= */ -static int readable (const char *fname) { - FILE *f = fopen(fname, "r"); /* try to open file */ +static int readable (const char *filename) { + FILE *f = fopen(filename, "r"); /* try to open file */ if (f == NULL) return 0; /* open failed */ fclose(f); return 1; @@ -348,53 +354,85 @@ static const char *pushnexttemplate (lua_State *L, const char *path) { } -static const char *findfile (lua_State *L, const char *pname) { +static const char *findfile (lua_State *L, const char *name, + const char *pname) { const char *path; - const char *name = luaL_checkstring(L, 1); name = luaL_gsub(L, name, ".", LUA_DIRSEP); lua_getfield(L, LUA_ENVIRONINDEX, pname); path = lua_tostring(L, -1); if (path == NULL) luaL_error(L, LUA_QL("package.%s") " must be a string", pname); while ((path = pushnexttemplate(L, path)) != NULL) { - const char *fname; - fname = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); - if (readable(fname)) /* does file exist and is readable? */ - return fname; /* return that file name */ + const char *filename; + filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); + if (readable(filename)) /* does file exist and is readable? */ + return filename; /* return that file name */ lua_pop(L, 2); /* remove path template and file name */ } return NULL; /* not found */ } -static void loaderror (lua_State *L, const char *msg) { +static void loaderror (lua_State *L) { luaL_error(L, "error loading package " LUA_QS " (%s)", - lua_tostring(L, 1), msg); + lua_tostring(L, 1), lua_tostring(L, -1)); } static int loader_Lua (lua_State *L) { - const char *fname; - fname = findfile(L, "path"); - if (fname == NULL) return 0; /* library not found in this path */ - if (luaL_loadfile(L, fname) != 0) - loaderror(L, lua_tostring(L, -1)); + const char *filename; + const char *name = luaL_checkstring(L, 1); + filename = findfile(L, name, "path"); + if (filename == NULL) return 0; /* library not found in this path */ + if (luaL_loadfile(L, filename) != 0) + loaderror(L); return 1; /* library loaded successfully */ } +static const char *mkfuncname (lua_State *L, const char *modname) { + const char *funcname; + const char *mark = strchr(modname, *LUA_IGMARK); + if (mark) modname = mark + 1; + funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); + funcname = lua_pushfstring(L, POF"%s", funcname); + lua_remove(L, -2); /* remove 'gsub' result */ + return funcname; +} + + static int loader_C (lua_State *L) { const char *funcname; - const char *fname = findfile(L, "cpath"); - if (fname == NULL) return 0; /* library not found in this path */ - funcname = luaL_gsub(L, lua_tostring(L, 1), ".", LUA_OFSEP); - funcname = lua_pushfstring(L, POF"%s", funcname); - if (ll_loadfunc(L, fname, funcname) != 1) - loaderror(L, lua_tostring(L, -2)); + const char *name = luaL_checkstring(L, 1); + const char *filename = findfile(L, name, "cpath"); + if (filename == NULL) return 0; /* library not found in this path */ + funcname = mkfuncname(L, name); + if (ll_loadfunc(L, filename, funcname) != 0) + loaderror(L); return 1; /* library loaded successfully */ } +static int loader_Croot (lua_State *L) { + const char *funcname; + const char *filename; + const char *name = luaL_checkstring(L, 1); + const char *p = strchr(name, '.'); + int stat; + if (p == NULL) return 0; /* is root */ + lua_pushlstring(L, name, p - name); + filename = findfile(L, lua_tostring(L, -1), "cpath"); + if (filename == NULL) return 0; /* root not found */ + funcname = mkfuncname(L, name); + if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { + if (stat == ERRFUNC) return 0; /* function not found */ + else + loaderror(L); /* real error */ + } + return 1; +} + + static int loader_preload (lua_State *L) { lua_getfield(L, LUA_ENVIRONINDEX, "preload"); if (!lua_istable(L, -1)) @@ -440,36 +478,22 @@ static int require_aux (lua_State *L, const char *name) { } -static void require_check (lua_State *L, const char *name) { - if (!require_aux(L, name)) { /* error? */ - /* build and show error message */ - const char *msg; - lua_settop(L, 1); - lua_getfield(L, LUA_ENVIRONINDEX, "path"); - lua_getfield(L, LUA_ENVIRONINDEX, "cpath"); - msg = lua_pushfstring(L, - "package " LUA_QS " not found in following paths:\n" - " Lua path: %s\n" - " C path: %s\n", name, - lua_tostring(L, -2), lua_tostring(L, -1)); - msg = luaL_gsub(L, msg, LUA_PATHSEP, "\n "); - luaL_error(L, msg); - } -} - - static int ll_require (lua_State *L) { const char *name = luaL_checkstring(L, 1); - const char *pt; - /* load all parent modules */ - for (pt = name; (pt = strchr(pt, '.')) != NULL; pt++) { - lua_settop(L, 1); - lua_pushlstring(L, name, pt - name); - require_aux(L, lua_tostring(L, -1)); - } - require_check(L, name); /* load module itself */ + if (!require_aux(L, name)) /* error? */ + luaL_error(L, "package " LUA_QS " not found", name); return 1; } + +/* }====================================================== */ + + + +/* +** {====================================================== +** 'module' function +** ======================================================= +*/ static void setfenv (lua_State *L) { @@ -524,14 +548,14 @@ static int ll_module (lua_State *L) { return 0; } - /* }====================================================== */ + /* auxiliary mark (for internal use) */ #define AUXMARK "\1" -static void setpath (lua_State *L, const char *fname, const char *envname, +static void setpath (lua_State *L, const char *fieldname, const char *envname, const char *def) { const char *path = getenv(envname); if (path == NULL) /* no environment variable? */ @@ -544,7 +568,7 @@ static void setpath (lua_State *L, const char *fname, const char *envname, lua_remove(L, -2); } setprogdir(L); - lua_setfield(L, -2, fname); + lua_setfield(L, -2, fieldname); } @@ -556,7 +580,7 @@ static const luaL_reg ll_funcs[] = { static const lua_CFunction loaders[] = - {loader_preload, loader_Lua, loader_C, NULL}; + {loader_preload, loader_Lua, loader_C, loader_Croot, NULL}; LUALIB_API int luaopen_loadlib (lua_State *L) {