121d3294cSantirez /*
2*214adc50Santirez ** $Id: loadlib.c,v 1.52.1.4 2009/09/09 13:17:16 roberto Exp $
321d3294cSantirez ** Dynamic library loader for Lua
421d3294cSantirez ** See Copyright Notice in lua.h
521d3294cSantirez **
621d3294cSantirez ** This module contains an implementation of loadlib for Unix systems
721d3294cSantirez ** that have dlfcn, an implementation for Darwin (Mac OS X), an
821d3294cSantirez ** implementation for Windows, and a stub for other systems.
921d3294cSantirez */
1021d3294cSantirez
1121d3294cSantirez
1221d3294cSantirez #include <stdlib.h>
1321d3294cSantirez #include <string.h>
1421d3294cSantirez
1521d3294cSantirez
1621d3294cSantirez #define loadlib_c
1721d3294cSantirez #define LUA_LIB
1821d3294cSantirez
1921d3294cSantirez #include "lua.h"
2021d3294cSantirez
2121d3294cSantirez #include "lauxlib.h"
2221d3294cSantirez #include "lualib.h"
2321d3294cSantirez
2421d3294cSantirez
2521d3294cSantirez /* prefix for open functions in C libraries */
2621d3294cSantirez #define LUA_POF "luaopen_"
2721d3294cSantirez
2821d3294cSantirez /* separator for open functions in C libraries */
2921d3294cSantirez #define LUA_OFSEP "_"
3021d3294cSantirez
3121d3294cSantirez
3221d3294cSantirez #define LIBPREFIX "LOADLIB: "
3321d3294cSantirez
3421d3294cSantirez #define POF LUA_POF
3521d3294cSantirez #define LIB_FAIL "open"
3621d3294cSantirez
3721d3294cSantirez
3821d3294cSantirez /* error codes for ll_loadfunc */
3921d3294cSantirez #define ERRLIB 1
4021d3294cSantirez #define ERRFUNC 2
4121d3294cSantirez
4221d3294cSantirez #define setprogdir(L) ((void)0)
4321d3294cSantirez
4421d3294cSantirez
4521d3294cSantirez static void ll_unloadlib (void *lib);
4621d3294cSantirez static void *ll_load (lua_State *L, const char *path);
4721d3294cSantirez static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym);
4821d3294cSantirez
4921d3294cSantirez
5021d3294cSantirez
5121d3294cSantirez #if defined(LUA_DL_DLOPEN)
5221d3294cSantirez /*
5321d3294cSantirez ** {========================================================================
5421d3294cSantirez ** This is an implementation of loadlib based on the dlfcn interface.
5521d3294cSantirez ** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
5621d3294cSantirez ** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
5721d3294cSantirez ** as an emulation layer on top of native functions.
5821d3294cSantirez ** =========================================================================
5921d3294cSantirez */
6021d3294cSantirez
6121d3294cSantirez #include <dlfcn.h>
6221d3294cSantirez
ll_unloadlib(void * lib)6321d3294cSantirez static void ll_unloadlib (void *lib) {
6421d3294cSantirez dlclose(lib);
6521d3294cSantirez }
6621d3294cSantirez
6721d3294cSantirez
ll_load(lua_State * L,const char * path)6821d3294cSantirez static void *ll_load (lua_State *L, const char *path) {
6921d3294cSantirez void *lib = dlopen(path, RTLD_NOW);
7021d3294cSantirez if (lib == NULL) lua_pushstring(L, dlerror());
7121d3294cSantirez return lib;
7221d3294cSantirez }
7321d3294cSantirez
7421d3294cSantirez
ll_sym(lua_State * L,void * lib,const char * sym)7521d3294cSantirez static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
7621d3294cSantirez lua_CFunction f = (lua_CFunction)dlsym(lib, sym);
7721d3294cSantirez if (f == NULL) lua_pushstring(L, dlerror());
7821d3294cSantirez return f;
7921d3294cSantirez }
8021d3294cSantirez
8121d3294cSantirez /* }====================================================== */
8221d3294cSantirez
8321d3294cSantirez
8421d3294cSantirez
8521d3294cSantirez #elif defined(LUA_DL_DLL)
8621d3294cSantirez /*
8721d3294cSantirez ** {======================================================================
8821d3294cSantirez ** This is an implementation of loadlib for Windows using native functions.
8921d3294cSantirez ** =======================================================================
9021d3294cSantirez */
9121d3294cSantirez
9221d3294cSantirez #include <windows.h>
9321d3294cSantirez
9421d3294cSantirez
9521d3294cSantirez #undef setprogdir
9621d3294cSantirez
setprogdir(lua_State * L)9721d3294cSantirez static void setprogdir (lua_State *L) {
9821d3294cSantirez char buff[MAX_PATH + 1];
9921d3294cSantirez char *lb;
10021d3294cSantirez DWORD nsize = sizeof(buff)/sizeof(char);
10121d3294cSantirez DWORD n = GetModuleFileNameA(NULL, buff, nsize);
10221d3294cSantirez if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL)
10321d3294cSantirez luaL_error(L, "unable to get ModuleFileName");
10421d3294cSantirez else {
10521d3294cSantirez *lb = '\0';
10621d3294cSantirez luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff);
10721d3294cSantirez lua_remove(L, -2); /* remove original string */
10821d3294cSantirez }
10921d3294cSantirez }
11021d3294cSantirez
11121d3294cSantirez
pusherror(lua_State * L)11221d3294cSantirez static void pusherror (lua_State *L) {
11321d3294cSantirez int error = GetLastError();
11421d3294cSantirez char buffer[128];
11521d3294cSantirez if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
11621d3294cSantirez NULL, error, 0, buffer, sizeof(buffer), NULL))
11721d3294cSantirez lua_pushstring(L, buffer);
11821d3294cSantirez else
11921d3294cSantirez lua_pushfstring(L, "system error %d\n", error);
12021d3294cSantirez }
12121d3294cSantirez
ll_unloadlib(void * lib)12221d3294cSantirez static void ll_unloadlib (void *lib) {
12321d3294cSantirez FreeLibrary((HINSTANCE)lib);
12421d3294cSantirez }
12521d3294cSantirez
12621d3294cSantirez
ll_load(lua_State * L,const char * path)12721d3294cSantirez static void *ll_load (lua_State *L, const char *path) {
12821d3294cSantirez HINSTANCE lib = LoadLibraryA(path);
12921d3294cSantirez if (lib == NULL) pusherror(L);
13021d3294cSantirez return lib;
13121d3294cSantirez }
13221d3294cSantirez
13321d3294cSantirez
ll_sym(lua_State * L,void * lib,const char * sym)13421d3294cSantirez static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
13521d3294cSantirez lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym);
13621d3294cSantirez if (f == NULL) pusherror(L);
13721d3294cSantirez return f;
13821d3294cSantirez }
13921d3294cSantirez
14021d3294cSantirez /* }====================================================== */
14121d3294cSantirez
14221d3294cSantirez
14321d3294cSantirez
14421d3294cSantirez #elif defined(LUA_DL_DYLD)
14521d3294cSantirez /*
14621d3294cSantirez ** {======================================================================
14721d3294cSantirez ** Native Mac OS X / Darwin Implementation
14821d3294cSantirez ** =======================================================================
14921d3294cSantirez */
15021d3294cSantirez
15121d3294cSantirez #include <mach-o/dyld.h>
15221d3294cSantirez
15321d3294cSantirez
15421d3294cSantirez /* Mac appends a `_' before C function names */
15521d3294cSantirez #undef POF
15621d3294cSantirez #define POF "_" LUA_POF
15721d3294cSantirez
15821d3294cSantirez
pusherror(lua_State * L)15921d3294cSantirez static void pusherror (lua_State *L) {
16021d3294cSantirez const char *err_str;
16121d3294cSantirez const char *err_file;
16221d3294cSantirez NSLinkEditErrors err;
16321d3294cSantirez int err_num;
16421d3294cSantirez NSLinkEditError(&err, &err_num, &err_file, &err_str);
16521d3294cSantirez lua_pushstring(L, err_str);
16621d3294cSantirez }
16721d3294cSantirez
16821d3294cSantirez
errorfromcode(NSObjectFileImageReturnCode ret)16921d3294cSantirez static const char *errorfromcode (NSObjectFileImageReturnCode ret) {
17021d3294cSantirez switch (ret) {
17121d3294cSantirez case NSObjectFileImageInappropriateFile:
17221d3294cSantirez return "file is not a bundle";
17321d3294cSantirez case NSObjectFileImageArch:
17421d3294cSantirez return "library is for wrong CPU type";
17521d3294cSantirez case NSObjectFileImageFormat:
17621d3294cSantirez return "bad format";
17721d3294cSantirez case NSObjectFileImageAccess:
17821d3294cSantirez return "cannot access file";
17921d3294cSantirez case NSObjectFileImageFailure:
18021d3294cSantirez default:
18121d3294cSantirez return "unable to load library";
18221d3294cSantirez }
18321d3294cSantirez }
18421d3294cSantirez
18521d3294cSantirez
ll_unloadlib(void * lib)18621d3294cSantirez static void ll_unloadlib (void *lib) {
18721d3294cSantirez NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
18821d3294cSantirez }
18921d3294cSantirez
19021d3294cSantirez
ll_load(lua_State * L,const char * path)19121d3294cSantirez static void *ll_load (lua_State *L, const char *path) {
19221d3294cSantirez NSObjectFileImage img;
19321d3294cSantirez NSObjectFileImageReturnCode ret;
19421d3294cSantirez /* this would be a rare case, but prevents crashing if it happens */
19521d3294cSantirez if(!_dyld_present()) {
19621d3294cSantirez lua_pushliteral(L, "dyld not present");
19721d3294cSantirez return NULL;
19821d3294cSantirez }
19921d3294cSantirez ret = NSCreateObjectFileImageFromFile(path, &img);
20021d3294cSantirez if (ret == NSObjectFileImageSuccess) {
20121d3294cSantirez NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE |
20221d3294cSantirez NSLINKMODULE_OPTION_RETURN_ON_ERROR);
20321d3294cSantirez NSDestroyObjectFileImage(img);
20421d3294cSantirez if (mod == NULL) pusherror(L);
20521d3294cSantirez return mod;
20621d3294cSantirez }
20721d3294cSantirez lua_pushstring(L, errorfromcode(ret));
20821d3294cSantirez return NULL;
20921d3294cSantirez }
21021d3294cSantirez
21121d3294cSantirez
ll_sym(lua_State * L,void * lib,const char * sym)21221d3294cSantirez static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
21321d3294cSantirez NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym);
21421d3294cSantirez if (nss == NULL) {
21521d3294cSantirez lua_pushfstring(L, "symbol " LUA_QS " not found", sym);
21621d3294cSantirez return NULL;
21721d3294cSantirez }
21821d3294cSantirez return (lua_CFunction)NSAddressOfSymbol(nss);
21921d3294cSantirez }
22021d3294cSantirez
22121d3294cSantirez /* }====================================================== */
22221d3294cSantirez
22321d3294cSantirez
22421d3294cSantirez
22521d3294cSantirez #else
22621d3294cSantirez /*
22721d3294cSantirez ** {======================================================
22821d3294cSantirez ** Fallback for other systems
22921d3294cSantirez ** =======================================================
23021d3294cSantirez */
23121d3294cSantirez
23221d3294cSantirez #undef LIB_FAIL
23321d3294cSantirez #define LIB_FAIL "absent"
23421d3294cSantirez
23521d3294cSantirez
23621d3294cSantirez #define DLMSG "dynamic libraries not enabled; check your Lua installation"
23721d3294cSantirez
23821d3294cSantirez
ll_unloadlib(void * lib)23921d3294cSantirez static void ll_unloadlib (void *lib) {
24021d3294cSantirez (void)lib; /* to avoid warnings */
24121d3294cSantirez }
24221d3294cSantirez
24321d3294cSantirez
ll_load(lua_State * L,const char * path)24421d3294cSantirez static void *ll_load (lua_State *L, const char *path) {
24521d3294cSantirez (void)path; /* to avoid warnings */
24621d3294cSantirez lua_pushliteral(L, DLMSG);
24721d3294cSantirez return NULL;
24821d3294cSantirez }
24921d3294cSantirez
25021d3294cSantirez
ll_sym(lua_State * L,void * lib,const char * sym)25121d3294cSantirez static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
25221d3294cSantirez (void)lib; (void)sym; /* to avoid warnings */
25321d3294cSantirez lua_pushliteral(L, DLMSG);
25421d3294cSantirez return NULL;
25521d3294cSantirez }
25621d3294cSantirez
25721d3294cSantirez /* }====================================================== */
25821d3294cSantirez #endif
25921d3294cSantirez
26021d3294cSantirez
26121d3294cSantirez
ll_register(lua_State * L,const char * path)26221d3294cSantirez static void **ll_register (lua_State *L, const char *path) {
26321d3294cSantirez void **plib;
26421d3294cSantirez lua_pushfstring(L, "%s%s", LIBPREFIX, path);
26521d3294cSantirez lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */
26621d3294cSantirez if (!lua_isnil(L, -1)) /* is there an entry? */
26721d3294cSantirez plib = (void **)lua_touserdata(L, -1);
26821d3294cSantirez else { /* no entry yet; create one */
26921d3294cSantirez lua_pop(L, 1);
27021d3294cSantirez plib = (void **)lua_newuserdata(L, sizeof(const void *));
27121d3294cSantirez *plib = NULL;
27221d3294cSantirez luaL_getmetatable(L, "_LOADLIB");
27321d3294cSantirez lua_setmetatable(L, -2);
27421d3294cSantirez lua_pushfstring(L, "%s%s", LIBPREFIX, path);
27521d3294cSantirez lua_pushvalue(L, -2);
27621d3294cSantirez lua_settable(L, LUA_REGISTRYINDEX);
27721d3294cSantirez }
27821d3294cSantirez return plib;
27921d3294cSantirez }
28021d3294cSantirez
28121d3294cSantirez
28221d3294cSantirez /*
28321d3294cSantirez ** __gc tag method: calls library's `ll_unloadlib' function with the lib
28421d3294cSantirez ** handle
28521d3294cSantirez */
gctm(lua_State * L)28621d3294cSantirez static int gctm (lua_State *L) {
28721d3294cSantirez void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB");
28821d3294cSantirez if (*lib) ll_unloadlib(*lib);
28921d3294cSantirez *lib = NULL; /* mark library as closed */
29021d3294cSantirez return 0;
29121d3294cSantirez }
29221d3294cSantirez
29321d3294cSantirez
ll_loadfunc(lua_State * L,const char * path,const char * sym)29421d3294cSantirez static int ll_loadfunc (lua_State *L, const char *path, const char *sym) {
29521d3294cSantirez void **reg = ll_register(L, path);
29621d3294cSantirez if (*reg == NULL) *reg = ll_load(L, path);
29721d3294cSantirez if (*reg == NULL)
29821d3294cSantirez return ERRLIB; /* unable to load library */
29921d3294cSantirez else {
30021d3294cSantirez lua_CFunction f = ll_sym(L, *reg, sym);
30121d3294cSantirez if (f == NULL)
30221d3294cSantirez return ERRFUNC; /* unable to find function */
30321d3294cSantirez lua_pushcfunction(L, f);
30421d3294cSantirez return 0; /* return function */
30521d3294cSantirez }
30621d3294cSantirez }
30721d3294cSantirez
30821d3294cSantirez
ll_loadlib(lua_State * L)30921d3294cSantirez static int ll_loadlib (lua_State *L) {
31021d3294cSantirez const char *path = luaL_checkstring(L, 1);
31121d3294cSantirez const char *init = luaL_checkstring(L, 2);
31221d3294cSantirez int stat = ll_loadfunc(L, path, init);
31321d3294cSantirez if (stat == 0) /* no errors? */
31421d3294cSantirez return 1; /* return the loaded function */
31521d3294cSantirez else { /* error; error message is on stack top */
31621d3294cSantirez lua_pushnil(L);
31721d3294cSantirez lua_insert(L, -2);
31821d3294cSantirez lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init");
31921d3294cSantirez return 3; /* return nil, error message, and where */
32021d3294cSantirez }
32121d3294cSantirez }
32221d3294cSantirez
32321d3294cSantirez
32421d3294cSantirez
32521d3294cSantirez /*
32621d3294cSantirez ** {======================================================
32721d3294cSantirez ** 'require' function
32821d3294cSantirez ** =======================================================
32921d3294cSantirez */
33021d3294cSantirez
33121d3294cSantirez
readable(const char * filename)33221d3294cSantirez static int readable (const char *filename) {
33321d3294cSantirez FILE *f = fopen(filename, "r"); /* try to open file */
33421d3294cSantirez if (f == NULL) return 0; /* open failed */
33521d3294cSantirez fclose(f);
33621d3294cSantirez return 1;
33721d3294cSantirez }
33821d3294cSantirez
33921d3294cSantirez
pushnexttemplate(lua_State * L,const char * path)34021d3294cSantirez static const char *pushnexttemplate (lua_State *L, const char *path) {
34121d3294cSantirez const char *l;
34221d3294cSantirez while (*path == *LUA_PATHSEP) path++; /* skip separators */
34321d3294cSantirez if (*path == '\0') return NULL; /* no more templates */
34421d3294cSantirez l = strchr(path, *LUA_PATHSEP); /* find next separator */
34521d3294cSantirez if (l == NULL) l = path + strlen(path);
34621d3294cSantirez lua_pushlstring(L, path, l - path); /* template */
34721d3294cSantirez return l;
34821d3294cSantirez }
34921d3294cSantirez
35021d3294cSantirez
findfile(lua_State * L,const char * name,const char * pname)35121d3294cSantirez static const char *findfile (lua_State *L, const char *name,
35221d3294cSantirez const char *pname) {
35321d3294cSantirez const char *path;
35421d3294cSantirez name = luaL_gsub(L, name, ".", LUA_DIRSEP);
35521d3294cSantirez lua_getfield(L, LUA_ENVIRONINDEX, pname);
35621d3294cSantirez path = lua_tostring(L, -1);
35721d3294cSantirez if (path == NULL)
35821d3294cSantirez luaL_error(L, LUA_QL("package.%s") " must be a string", pname);
35921d3294cSantirez lua_pushliteral(L, ""); /* error accumulator */
36021d3294cSantirez while ((path = pushnexttemplate(L, path)) != NULL) {
36121d3294cSantirez const char *filename;
36221d3294cSantirez filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name);
36321d3294cSantirez lua_remove(L, -2); /* remove path template */
36421d3294cSantirez if (readable(filename)) /* does file exist and is readable? */
36521d3294cSantirez return filename; /* return that file name */
36621d3294cSantirez lua_pushfstring(L, "\n\tno file " LUA_QS, filename);
36721d3294cSantirez lua_remove(L, -2); /* remove file name */
36821d3294cSantirez lua_concat(L, 2); /* add entry to possible error message */
36921d3294cSantirez }
37021d3294cSantirez return NULL; /* not found */
37121d3294cSantirez }
37221d3294cSantirez
37321d3294cSantirez
loaderror(lua_State * L,const char * filename)37421d3294cSantirez static void loaderror (lua_State *L, const char *filename) {
37521d3294cSantirez luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s",
37621d3294cSantirez lua_tostring(L, 1), filename, lua_tostring(L, -1));
37721d3294cSantirez }
37821d3294cSantirez
37921d3294cSantirez
loader_Lua(lua_State * L)38021d3294cSantirez static int loader_Lua (lua_State *L) {
38121d3294cSantirez const char *filename;
38221d3294cSantirez const char *name = luaL_checkstring(L, 1);
38321d3294cSantirez filename = findfile(L, name, "path");
38421d3294cSantirez if (filename == NULL) return 1; /* library not found in this path */
38521d3294cSantirez if (luaL_loadfile(L, filename) != 0)
38621d3294cSantirez loaderror(L, filename);
38721d3294cSantirez return 1; /* library loaded successfully */
38821d3294cSantirez }
38921d3294cSantirez
39021d3294cSantirez
mkfuncname(lua_State * L,const char * modname)39121d3294cSantirez static const char *mkfuncname (lua_State *L, const char *modname) {
39221d3294cSantirez const char *funcname;
39321d3294cSantirez const char *mark = strchr(modname, *LUA_IGMARK);
39421d3294cSantirez if (mark) modname = mark + 1;
39521d3294cSantirez funcname = luaL_gsub(L, modname, ".", LUA_OFSEP);
39621d3294cSantirez funcname = lua_pushfstring(L, POF"%s", funcname);
39721d3294cSantirez lua_remove(L, -2); /* remove 'gsub' result */
39821d3294cSantirez return funcname;
39921d3294cSantirez }
40021d3294cSantirez
40121d3294cSantirez
loader_C(lua_State * L)40221d3294cSantirez static int loader_C (lua_State *L) {
40321d3294cSantirez const char *funcname;
40421d3294cSantirez const char *name = luaL_checkstring(L, 1);
40521d3294cSantirez const char *filename = findfile(L, name, "cpath");
40621d3294cSantirez if (filename == NULL) return 1; /* library not found in this path */
40721d3294cSantirez funcname = mkfuncname(L, name);
40821d3294cSantirez if (ll_loadfunc(L, filename, funcname) != 0)
40921d3294cSantirez loaderror(L, filename);
41021d3294cSantirez return 1; /* library loaded successfully */
41121d3294cSantirez }
41221d3294cSantirez
41321d3294cSantirez
loader_Croot(lua_State * L)41421d3294cSantirez static int loader_Croot (lua_State *L) {
41521d3294cSantirez const char *funcname;
41621d3294cSantirez const char *filename;
41721d3294cSantirez const char *name = luaL_checkstring(L, 1);
41821d3294cSantirez const char *p = strchr(name, '.');
41921d3294cSantirez int stat;
42021d3294cSantirez if (p == NULL) return 0; /* is root */
42121d3294cSantirez lua_pushlstring(L, name, p - name);
42221d3294cSantirez filename = findfile(L, lua_tostring(L, -1), "cpath");
42321d3294cSantirez if (filename == NULL) return 1; /* root not found */
42421d3294cSantirez funcname = mkfuncname(L, name);
42521d3294cSantirez if ((stat = ll_loadfunc(L, filename, funcname)) != 0) {
42621d3294cSantirez if (stat != ERRFUNC) loaderror(L, filename); /* real error */
42721d3294cSantirez lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS,
42821d3294cSantirez name, filename);
42921d3294cSantirez return 1; /* function not found */
43021d3294cSantirez }
43121d3294cSantirez return 1;
43221d3294cSantirez }
43321d3294cSantirez
43421d3294cSantirez
loader_preload(lua_State * L)43521d3294cSantirez static int loader_preload (lua_State *L) {
43621d3294cSantirez const char *name = luaL_checkstring(L, 1);
43721d3294cSantirez lua_getfield(L, LUA_ENVIRONINDEX, "preload");
43821d3294cSantirez if (!lua_istable(L, -1))
43921d3294cSantirez luaL_error(L, LUA_QL("package.preload") " must be a table");
44021d3294cSantirez lua_getfield(L, -1, name);
44121d3294cSantirez if (lua_isnil(L, -1)) /* not found? */
44221d3294cSantirez lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
44321d3294cSantirez return 1;
44421d3294cSantirez }
44521d3294cSantirez
44621d3294cSantirez
44721d3294cSantirez static const int sentinel_ = 0;
44821d3294cSantirez #define sentinel ((void *)&sentinel_)
44921d3294cSantirez
45021d3294cSantirez
ll_require(lua_State * L)45121d3294cSantirez static int ll_require (lua_State *L) {
45221d3294cSantirez const char *name = luaL_checkstring(L, 1);
45321d3294cSantirez int i;
45421d3294cSantirez lua_settop(L, 1); /* _LOADED table will be at index 2 */
45521d3294cSantirez lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
45621d3294cSantirez lua_getfield(L, 2, name);
45721d3294cSantirez if (lua_toboolean(L, -1)) { /* is it there? */
45821d3294cSantirez if (lua_touserdata(L, -1) == sentinel) /* check loops */
45921d3294cSantirez luaL_error(L, "loop or previous error loading module " LUA_QS, name);
46021d3294cSantirez return 1; /* package is already loaded */
46121d3294cSantirez }
46221d3294cSantirez /* else must load it; iterate over available loaders */
46321d3294cSantirez lua_getfield(L, LUA_ENVIRONINDEX, "loaders");
46421d3294cSantirez if (!lua_istable(L, -1))
46521d3294cSantirez luaL_error(L, LUA_QL("package.loaders") " must be a table");
46621d3294cSantirez lua_pushliteral(L, ""); /* error message accumulator */
46721d3294cSantirez for (i=1; ; i++) {
46821d3294cSantirez lua_rawgeti(L, -2, i); /* get a loader */
46921d3294cSantirez if (lua_isnil(L, -1))
47021d3294cSantirez luaL_error(L, "module " LUA_QS " not found:%s",
47121d3294cSantirez name, lua_tostring(L, -2));
47221d3294cSantirez lua_pushstring(L, name);
47321d3294cSantirez lua_call(L, 1, 1); /* call it */
47421d3294cSantirez if (lua_isfunction(L, -1)) /* did it find module? */
47521d3294cSantirez break; /* module loaded successfully */
47621d3294cSantirez else if (lua_isstring(L, -1)) /* loader returned error message? */
47721d3294cSantirez lua_concat(L, 2); /* accumulate it */
47821d3294cSantirez else
47921d3294cSantirez lua_pop(L, 1);
48021d3294cSantirez }
48121d3294cSantirez lua_pushlightuserdata(L, sentinel);
48221d3294cSantirez lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */
48321d3294cSantirez lua_pushstring(L, name); /* pass name as argument to module */
48421d3294cSantirez lua_call(L, 1, 1); /* run loaded module */
48521d3294cSantirez if (!lua_isnil(L, -1)) /* non-nil return? */
48621d3294cSantirez lua_setfield(L, 2, name); /* _LOADED[name] = returned value */
48721d3294cSantirez lua_getfield(L, 2, name);
48821d3294cSantirez if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */
48921d3294cSantirez lua_pushboolean(L, 1); /* use true as result */
49021d3294cSantirez lua_pushvalue(L, -1); /* extra copy to be returned */
49121d3294cSantirez lua_setfield(L, 2, name); /* _LOADED[name] = true */
49221d3294cSantirez }
49321d3294cSantirez return 1;
49421d3294cSantirez }
49521d3294cSantirez
49621d3294cSantirez /* }====================================================== */
49721d3294cSantirez
49821d3294cSantirez
49921d3294cSantirez
50021d3294cSantirez /*
50121d3294cSantirez ** {======================================================
50221d3294cSantirez ** 'module' function
50321d3294cSantirez ** =======================================================
50421d3294cSantirez */
50521d3294cSantirez
50621d3294cSantirez
setfenv(lua_State * L)50721d3294cSantirez static void setfenv (lua_State *L) {
50821d3294cSantirez lua_Debug ar;
50921d3294cSantirez if (lua_getstack(L, 1, &ar) == 0 ||
51021d3294cSantirez lua_getinfo(L, "f", &ar) == 0 || /* get calling function */
51121d3294cSantirez lua_iscfunction(L, -1))
51221d3294cSantirez luaL_error(L, LUA_QL("module") " not called from a Lua function");
51321d3294cSantirez lua_pushvalue(L, -2);
51421d3294cSantirez lua_setfenv(L, -2);
51521d3294cSantirez lua_pop(L, 1);
51621d3294cSantirez }
51721d3294cSantirez
51821d3294cSantirez
dooptions(lua_State * L,int n)51921d3294cSantirez static void dooptions (lua_State *L, int n) {
52021d3294cSantirez int i;
52121d3294cSantirez for (i = 2; i <= n; i++) {
52221d3294cSantirez lua_pushvalue(L, i); /* get option (a function) */
52321d3294cSantirez lua_pushvalue(L, -2); /* module */
52421d3294cSantirez lua_call(L, 1, 0);
52521d3294cSantirez }
52621d3294cSantirez }
52721d3294cSantirez
52821d3294cSantirez
modinit(lua_State * L,const char * modname)52921d3294cSantirez static void modinit (lua_State *L, const char *modname) {
53021d3294cSantirez const char *dot;
53121d3294cSantirez lua_pushvalue(L, -1);
53221d3294cSantirez lua_setfield(L, -2, "_M"); /* module._M = module */
53321d3294cSantirez lua_pushstring(L, modname);
53421d3294cSantirez lua_setfield(L, -2, "_NAME");
53521d3294cSantirez dot = strrchr(modname, '.'); /* look for last dot in module name */
53621d3294cSantirez if (dot == NULL) dot = modname;
53721d3294cSantirez else dot++;
53821d3294cSantirez /* set _PACKAGE as package name (full module name minus last part) */
53921d3294cSantirez lua_pushlstring(L, modname, dot - modname);
54021d3294cSantirez lua_setfield(L, -2, "_PACKAGE");
54121d3294cSantirez }
54221d3294cSantirez
54321d3294cSantirez
ll_module(lua_State * L)54421d3294cSantirez static int ll_module (lua_State *L) {
54521d3294cSantirez const char *modname = luaL_checkstring(L, 1);
54621d3294cSantirez int loaded = lua_gettop(L) + 1; /* index of _LOADED table */
54721d3294cSantirez lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
54821d3294cSantirez lua_getfield(L, loaded, modname); /* get _LOADED[modname] */
54921d3294cSantirez if (!lua_istable(L, -1)) { /* not found? */
55021d3294cSantirez lua_pop(L, 1); /* remove previous result */
55121d3294cSantirez /* try global variable (and create one if it does not exist) */
55221d3294cSantirez if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL)
55321d3294cSantirez return luaL_error(L, "name conflict for module " LUA_QS, modname);
55421d3294cSantirez lua_pushvalue(L, -1);
55521d3294cSantirez lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */
55621d3294cSantirez }
55721d3294cSantirez /* check whether table already has a _NAME field */
55821d3294cSantirez lua_getfield(L, -1, "_NAME");
55921d3294cSantirez if (!lua_isnil(L, -1)) /* is table an initialized module? */
56021d3294cSantirez lua_pop(L, 1);
56121d3294cSantirez else { /* no; initialize it */
56221d3294cSantirez lua_pop(L, 1);
56321d3294cSantirez modinit(L, modname);
56421d3294cSantirez }
56521d3294cSantirez lua_pushvalue(L, -1);
56621d3294cSantirez setfenv(L);
56721d3294cSantirez dooptions(L, loaded - 1);
56821d3294cSantirez return 0;
56921d3294cSantirez }
57021d3294cSantirez
57121d3294cSantirez
ll_seeall(lua_State * L)57221d3294cSantirez static int ll_seeall (lua_State *L) {
57321d3294cSantirez luaL_checktype(L, 1, LUA_TTABLE);
57421d3294cSantirez if (!lua_getmetatable(L, 1)) {
57521d3294cSantirez lua_createtable(L, 0, 1); /* create new metatable */
57621d3294cSantirez lua_pushvalue(L, -1);
57721d3294cSantirez lua_setmetatable(L, 1);
57821d3294cSantirez }
57921d3294cSantirez lua_pushvalue(L, LUA_GLOBALSINDEX);
58021d3294cSantirez lua_setfield(L, -2, "__index"); /* mt.__index = _G */
58121d3294cSantirez return 0;
58221d3294cSantirez }
58321d3294cSantirez
58421d3294cSantirez
58521d3294cSantirez /* }====================================================== */
58621d3294cSantirez
58721d3294cSantirez
58821d3294cSantirez
58921d3294cSantirez /* auxiliary mark (for internal use) */
59021d3294cSantirez #define AUXMARK "\1"
59121d3294cSantirez
setpath(lua_State * L,const char * fieldname,const char * envname,const char * def)59221d3294cSantirez static void setpath (lua_State *L, const char *fieldname, const char *envname,
59321d3294cSantirez const char *def) {
59421d3294cSantirez const char *path = getenv(envname);
59521d3294cSantirez if (path == NULL) /* no environment variable? */
59621d3294cSantirez lua_pushstring(L, def); /* use default */
59721d3294cSantirez else {
59821d3294cSantirez /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */
59921d3294cSantirez path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP,
60021d3294cSantirez LUA_PATHSEP AUXMARK LUA_PATHSEP);
60121d3294cSantirez luaL_gsub(L, path, AUXMARK, def);
60221d3294cSantirez lua_remove(L, -2);
60321d3294cSantirez }
60421d3294cSantirez setprogdir(L);
60521d3294cSantirez lua_setfield(L, -2, fieldname);
60621d3294cSantirez }
60721d3294cSantirez
60821d3294cSantirez
60921d3294cSantirez static const luaL_Reg pk_funcs[] = {
61021d3294cSantirez {"loadlib", ll_loadlib},
61121d3294cSantirez {"seeall", ll_seeall},
61221d3294cSantirez {NULL, NULL}
61321d3294cSantirez };
61421d3294cSantirez
61521d3294cSantirez
61621d3294cSantirez static const luaL_Reg ll_funcs[] = {
61721d3294cSantirez {"module", ll_module},
61821d3294cSantirez {"require", ll_require},
61921d3294cSantirez {NULL, NULL}
62021d3294cSantirez };
62121d3294cSantirez
62221d3294cSantirez
62321d3294cSantirez static const lua_CFunction loaders[] =
62421d3294cSantirez {loader_preload, loader_Lua, loader_C, loader_Croot, NULL};
62521d3294cSantirez
62621d3294cSantirez
luaopen_package(lua_State * L)62721d3294cSantirez LUALIB_API int luaopen_package (lua_State *L) {
62821d3294cSantirez int i;
62921d3294cSantirez /* create new type _LOADLIB */
63021d3294cSantirez luaL_newmetatable(L, "_LOADLIB");
63121d3294cSantirez lua_pushcfunction(L, gctm);
63221d3294cSantirez lua_setfield(L, -2, "__gc");
63321d3294cSantirez /* create `package' table */
63421d3294cSantirez luaL_register(L, LUA_LOADLIBNAME, pk_funcs);
63521d3294cSantirez #if defined(LUA_COMPAT_LOADLIB)
63621d3294cSantirez lua_getfield(L, -1, "loadlib");
63721d3294cSantirez lua_setfield(L, LUA_GLOBALSINDEX, "loadlib");
63821d3294cSantirez #endif
63921d3294cSantirez lua_pushvalue(L, -1);
64021d3294cSantirez lua_replace(L, LUA_ENVIRONINDEX);
64121d3294cSantirez /* create `loaders' table */
642*214adc50Santirez lua_createtable(L, sizeof(loaders)/sizeof(loaders[0]) - 1, 0);
64321d3294cSantirez /* fill it with pre-defined loaders */
64421d3294cSantirez for (i=0; loaders[i] != NULL; i++) {
64521d3294cSantirez lua_pushcfunction(L, loaders[i]);
64621d3294cSantirez lua_rawseti(L, -2, i+1);
64721d3294cSantirez }
64821d3294cSantirez lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */
64921d3294cSantirez setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */
65021d3294cSantirez setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */
65121d3294cSantirez /* store config information */
65221d3294cSantirez lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n"
65321d3294cSantirez LUA_EXECDIR "\n" LUA_IGMARK);
65421d3294cSantirez lua_setfield(L, -2, "config");
65521d3294cSantirez /* set field `loaded' */
65621d3294cSantirez luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2);
65721d3294cSantirez lua_setfield(L, -2, "loaded");
65821d3294cSantirez /* set field `preload' */
65921d3294cSantirez lua_newtable(L);
66021d3294cSantirez lua_setfield(L, -2, "preload");
66121d3294cSantirez lua_pushvalue(L, LUA_GLOBALSINDEX);
66221d3294cSantirez luaL_register(L, NULL, ll_funcs); /* open lib into global table */
66321d3294cSantirez lua_pop(L, 1);
66421d3294cSantirez return 1; /* return 'package' table */
66521d3294cSantirez }
66621d3294cSantirez
667