1 /*
2 ** $Id$
3 ** Dynamic library loader for Lua
4 ** See Copyright Notice in lua.h
5 **
6 ** This module contains an implementation of loadlib for Unix systems
7 ** that have dlfcn, an implementation for Darwin (Mac OS X), an
8 ** implementation for Windows, and a stub for other systems.
9 */
10 
11 
12 #define loadlib_c
13 #define LUA_LIB
14 
15 #include "lua.h"
16 
17 #include "lauxlib.h"
18 #include "lualib.h"
19 
20 
21 /* prefix for open functions in C libraries */
22 #define LUA_POF		"luaopen_"
23 
24 /* separator for open functions in C libraries */
25 #define LUA_OFSEP	"_"
26 
27 
28 #define LIBPREFIX	"LOADLIB: "
29 
30 #define POF		LUA_POF
31 #define LIB_FAIL	"open"
32 
33 
34 /*
35 ** {======================================================
36 ** Fallback for other systems
37 ** =======================================================
38 */
39 
40 #undef LIB_FAIL
41 #define LIB_FAIL	"absent"
42 
43 
44 #define DLMSG	"dynamic libraries not enabled; check your Lua installation"
45 
46 
47 /* }====================================================== */
48 
49 
50 
ll_register(lua_State * L,const char * path)51 static void **ll_register (lua_State *L, const char *path) {
52   void **plib;
53   lua_pushfstring(L, "%s%s", LIBPREFIX, path);
54   lua_gettable(L, LUA_REGISTRYINDEX);  /* check library in registry? */
55   if (!lua_isnil(L, -1))  /* is there an entry? */
56     plib = (void **)lua_touserdata(L, -1);
57   else {  /* no entry yet; create one */
58     lua_pop(L, 1);
59     plib = (void **)lua_newuserdata(L, sizeof(const void *));
60     *plib = NULL;
61     luaL_getmetatable(L, "_LOADLIB");
62     lua_setmetatable(L, -2);
63     lua_pushfstring(L, "%s%s", LIBPREFIX, path);
64     lua_pushvalue(L, -2);
65     lua_settable(L, LUA_REGISTRYINDEX);
66   }
67   return plib;
68 }
69 
70 
71 /*
72 ** __gc tag method: calls library's `ll_unloadlib' function with the lib
73 ** handle
74 */
gctm(lua_State * L)75 static int gctm (lua_State *L) {
76   void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB");
77   *lib = NULL;  /* mark library as closed */
78   return 0;
79 }
80 
81 
82 /* error codes for ll_loadfunc */
83 #define ERRLIB		1
84 #define ERRFUNC		2
85 
86 
ll_loadlib(lua_State * L)87 static int ll_loadlib (lua_State *L) {
88   const char *path = luaL_checkstring(L, 1);
89 //  const char *init = luaL_checkstring(L, 2);
90   int stat;
91   void **reg = ll_register(L, path);
92   if (*reg == NULL) {
93     stat = ERRLIB;  /* unable to load library */
94   } else {
95     stat = ERRFUNC;  /* unable to find function */
96   }
97   lua_pushliteral(L, DLMSG);
98 
99   /* error; error message is on stack top */
100   lua_pushnil(L);
101   lua_insert(L, -2);
102   lua_pushstring(L, (stat == ERRLIB) ?  LIB_FAIL : "init");
103   return 3;  /* return nil, error message, and where */
104 }
105 
106 
107 
108 /*
109 ** {======================================================
110 ** 'require' function
111 ** =======================================================
112 */
113 
114 
loader_preload(lua_State * L)115 static int loader_preload (lua_State *L) {
116   const char *name = luaL_checkstring(L, 1);
117   lua_getfield(L, LUA_ENVIRONINDEX, "preload");
118   if (!lua_istable(L, -1))
119     luaL_error(L, LUA_QL("package.preload") " must be a table");
120   lua_getfield(L, -1, name);
121   if (lua_isnil(L, -1))  /* not found? */
122     lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
123   return 1;
124 }
125 
126 
127 static /*const*/ int sentinel_ = 0;
128 #define sentinel	((void *)&sentinel_)
129 
130 
ll_require(lua_State * L)131 static int ll_require (lua_State *L) {
132   const char *name = luaL_checkstring(L, 1);
133   int i;
134   lua_settop(L, 1);  /* _LOADED table will be at index 2 */
135   lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
136   lua_getfield(L, 2, name);
137   if (lua_toboolean(L, -1)) {  /* is it there? */
138     if (lua_touserdata(L, -1) == sentinel)  /* check loops */
139       luaL_error(L, "loop or previous error loading module " LUA_QS, name);
140     return 1;  /* package is already loaded */
141   }
142   /* else must load it; iterate over available loaders */
143   lua_getfield(L, LUA_ENVIRONINDEX, "loaders");
144   if (!lua_istable(L, -1))
145     luaL_error(L, LUA_QL("package.loaders") " must be a table");
146   lua_pushliteral(L, "");  /* error message accumulator */
147   for (i=1; ; i++) {
148     lua_rawgeti(L, -2, i);  /* get a loader */
149     if (lua_isnil(L, -1))
150       luaL_error(L, "module " LUA_QS " not found:%s",
151                     name, lua_tostring(L, -2));
152     lua_pushstring(L, name);
153     lua_call(L, 1, 1);  /* call it */
154     if (lua_isfunction(L, -1))  /* did it find module? */
155       break;  /* module loaded successfully */
156     else if (lua_isstring(L, -1))  /* loader returned error message? */
157       lua_concat(L, 2);  /* accumulate it */
158     else
159       lua_pop(L, 1);
160   }
161   lua_pushlightuserdata(L, sentinel);
162   lua_setfield(L, 2, name);  /* _LOADED[name] = sentinel */
163   lua_pushstring(L, name);  /* pass name as argument to module */
164   lua_call(L, 1, 1);  /* run loaded module */
165   if (!lua_isnil(L, -1))  /* non-nil return? */
166     lua_setfield(L, 2, name);  /* _LOADED[name] = returned value */
167   lua_getfield(L, 2, name);
168   if (lua_touserdata(L, -1) == sentinel) {   /* module did not set a value? */
169     lua_pushboolean(L, 1);  /* use true as result */
170     lua_pushvalue(L, -1);  /* extra copy to be returned */
171     lua_setfield(L, 2, name);  /* _LOADED[name] = true */
172   }
173   return 1;
174 }
175 
176 /* }====================================================== */
177 
178 
179 
180 /*
181 ** {======================================================
182 ** 'module' function
183 ** =======================================================
184 */
185 
186 
setfenv(lua_State * L)187 static void setfenv (lua_State *L) {
188   lua_Debug ar;
189   lua_getstack(L, 1, &ar);
190   lua_getinfo(L, "f", &ar);
191   lua_pushvalue(L, -2);
192   lua_setfenv(L, -2);
193   lua_pop(L, 1);
194 }
195 
196 
dooptions(lua_State * L,int n)197 static void dooptions (lua_State *L, int n) {
198   int i;
199   for (i = 2; i <= n; i++) {
200     lua_pushvalue(L, i);  /* get option (a function) */
201     lua_pushvalue(L, -2);  /* module */
202     lua_call(L, 1, 0);
203   }
204 }
205 
206 
modinit(lua_State * L,const char * modname)207 static void modinit (lua_State *L, const char *modname) {
208   const char *dot;
209   lua_pushvalue(L, -1);
210   lua_setfield(L, -2, "_M");  /* module._M = module */
211   lua_pushstring(L, modname);
212   lua_setfield(L, -2, "_NAME");
213   dot = strrchr(modname, '.');  /* look for last dot in module name */
214   if (dot == NULL) dot = modname;
215   else dot++;
216   /* set _PACKAGE as package name (full module name minus last part) */
217   lua_pushlstring(L, modname, dot - modname);
218   lua_setfield(L, -2, "_PACKAGE");
219 }
220 
221 
ll_module(lua_State * L)222 static int ll_module (lua_State *L) {
223   const char *modname = luaL_checkstring(L, 1);
224   int loaded = lua_gettop(L) + 1;  /* index of _LOADED table */
225   lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
226   lua_getfield(L, loaded, modname);  /* get _LOADED[modname] */
227   if (!lua_istable(L, -1)) {  /* not found? */
228     lua_pop(L, 1);  /* remove previous result */
229     /* try global variable (and create one if it does not exist) */
230     if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL)
231       return luaL_error(L, "name conflict for module " LUA_QS, modname);
232     lua_pushvalue(L, -1);
233     lua_setfield(L, loaded, modname);  /* _LOADED[modname] = new table */
234   }
235   /* check whether table already has a _NAME field */
236   lua_getfield(L, -1, "_NAME");
237   if (!lua_isnil(L, -1))  /* is table an initialized module? */
238     lua_pop(L, 1);
239   else {  /* no; initialize it */
240     lua_pop(L, 1);
241     modinit(L, modname);
242   }
243   lua_pushvalue(L, -1);
244   setfenv(L);
245   dooptions(L, loaded - 1);
246   return 0;
247 }
248 
249 
ll_seeall(lua_State * L)250 static int ll_seeall (lua_State *L) {
251   luaL_checktype(L, 1, LUA_TTABLE);
252   if (!lua_getmetatable(L, 1)) {
253     lua_createtable(L, 0, 1); /* create new metatable */
254     lua_pushvalue(L, -1);
255     lua_setmetatable(L, 1);
256   }
257   lua_pushvalue(L, LUA_GLOBALSINDEX);
258   lua_setfield(L, -2, "__index");  /* mt.__index = _G */
259   return 0;
260 }
261 
262 
263 /* }====================================================== */
264 
265 
266 
setpath(lua_State * L,const char * fieldname,const char * envname,const char * def)267 static void setpath (lua_State *L, const char *fieldname, const char *envname,
268                                    const char *def) {
269 	// no environment variable -> use default
270 	lua_pushstring(L, def);
271 	lua_setfield(L, -2, fieldname);
272 }
273 
274 
275 static const luaL_Reg pk_funcs[] = {
276   {"loadlib", ll_loadlib},
277   {"seeall", ll_seeall},
278   {NULL, NULL}
279 };
280 
281 
282 static const luaL_Reg ll_funcs[] = {
283   {"module", ll_module},
284   {"require", ll_require},
285   {NULL, NULL}
286 };
287 
288 
289 static const lua_CFunction loaders[] =
290   {loader_preload, NULL};
291 
292 
luaopen_package(lua_State * L)293 LUALIB_API int luaopen_package (lua_State *L) {
294   int i;
295   /* create new type _LOADLIB */
296   luaL_newmetatable(L, "_LOADLIB");
297   lua_pushcfunction(L, gctm);
298   lua_setfield(L, -2, "__gc");
299   /* create `package' table */
300   luaL_register(L, LUA_LOADLIBNAME, pk_funcs);
301 #if defined(LUA_COMPAT_LOADLIB)
302   lua_getfield(L, -1, "loadlib");
303   lua_setfield(L, LUA_GLOBALSINDEX, "loadlib");
304 #endif
305   lua_pushvalue(L, -1);
306   lua_replace(L, LUA_ENVIRONINDEX);
307   /* create `loaders' table */
308   lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1);
309   /* fill it with pre-defined loaders */
310   for (i=0; loaders[i] != NULL; i++) {
311     lua_pushcfunction(L, loaders[i]);
312     lua_rawseti(L, -2, i+1);
313   }
314   lua_setfield(L, -2, "loaders");  /* put it in field `loaders' */
315   setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT);  /* set field `path' */
316   setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */
317   /* store config information */
318   lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n"
319                      LUA_EXECDIR "\n" LUA_IGMARK);
320   lua_setfield(L, -2, "config");
321   /* set field `loaded' */
322   luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2);
323   lua_setfield(L, -2, "loaded");
324   /* set field `preload' */
325   lua_newtable(L);
326   lua_setfield(L, -2, "preload");
327   lua_pushvalue(L, LUA_GLOBALSINDEX);
328   luaL_register(L, NULL, ll_funcs);  /* open lib into global table */
329   lua_pop(L, 1);
330   return 1;  /* return 'package' table */
331 }
332