xref: /redis-3.2.3/deps/lua/src/loadlib.c (revision 214adc50)
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