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