1 | /* |
2 | ** Package library. |
3 | ** Copyright (C) 2005-2014 Mike Pall. See Copyright Notice in luajit.h |
4 | ** |
5 | ** Major portions taken verbatim or adapted from the Lua interpreter. |
6 | ** Copyright (C) 1994-2012 Lua.org, PUC-Rio. See Copyright Notice in lua.h |
7 | */ |
8 | |
9 | #define lib_package_c |
10 | #define LUA_LIB |
11 | |
12 | #include "lua.h" |
13 | #include "lauxlib.h" |
14 | #include "lualib.h" |
15 | |
16 | #include "lj_obj.h" |
17 | #include "lj_err.h" |
18 | #include "lj_lib.h" |
19 | |
20 | /* ------------------------------------------------------------------------ */ |
21 | |
22 | /* Error codes for ll_loadfunc. */ |
23 | #define PACKAGE_ERR_LIB 1 |
24 | #define PACKAGE_ERR_FUNC 2 |
25 | #define PACKAGE_ERR_LOAD 3 |
26 | |
27 | /* Redefined in platform specific part. */ |
28 | #define PACKAGE_LIB_FAIL "open" |
29 | #define setprogdir(L) ((void)0) |
30 | |
31 | /* Symbol name prefixes. */ |
32 | #define SYMPREFIX_CF "luaopen_%s" |
33 | #define SYMPREFIX_BC "luaJIT_BC_%s" |
34 | |
35 | #if LJ_TARGET_DLOPEN |
36 | |
37 | #include <dlfcn.h> |
38 | |
39 | static void ll_unloadlib(void *lib) |
40 | { |
41 | dlclose(lib); |
42 | } |
43 | |
44 | static void *ll_load(lua_State *L, const char *path, int gl) |
45 | { |
46 | void *lib = dlopen(path, RTLD_NOW | (gl ? RTLD_GLOBAL : RTLD_LOCAL)); |
47 | if (lib == NULL) lua_pushstring(L, dlerror()); |
48 | return lib; |
49 | } |
50 | |
51 | static lua_CFunction ll_sym(lua_State *L, void *lib, const char *sym) |
52 | { |
53 | lua_CFunction f = (lua_CFunction)dlsym(lib, sym); |
54 | if (f == NULL) lua_pushstring(L, dlerror()); |
55 | return f; |
56 | } |
57 | |
58 | static const char *ll_bcsym(void *lib, const char *sym) |
59 | { |
60 | #if defined(RTLD_DEFAULT) |
61 | if (lib == NULL) lib = RTLD_DEFAULT; |
62 | #elif LJ_TARGET_OSX || LJ_TARGET_BSD |
63 | if (lib == NULL) lib = (void *)(intptr_t)-2; |
64 | #endif |
65 | return (const char *)dlsym(lib, sym); |
66 | } |
67 | |
68 | #elif LJ_TARGET_WINDOWS |
69 | |
70 | #define WIN32_LEAN_AND_MEAN |
71 | #include <windows.h> |
72 | |
73 | #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
74 | #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4 |
75 | #define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2 |
76 | BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*); |
77 | #endif |
78 | |
79 | #undef setprogdir |
80 | |
81 | static void setprogdir(lua_State *L) |
82 | { |
83 | char buff[MAX_PATH + 1]; |
84 | char *lb; |
85 | DWORD nsize = sizeof(buff); |
86 | DWORD n = GetModuleFileNameA(NULL, buff, nsize); |
87 | if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) { |
88 | luaL_error(L, "unable to get ModuleFileName" ); |
89 | } else { |
90 | *lb = '\0'; |
91 | luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); |
92 | lua_remove(L, -2); /* remove original string */ |
93 | } |
94 | } |
95 | |
96 | static void pusherror(lua_State *L) |
97 | { |
98 | DWORD error = GetLastError(); |
99 | char buffer[128]; |
100 | if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, |
101 | NULL, error, 0, buffer, sizeof(buffer), NULL)) |
102 | lua_pushstring(L, buffer); |
103 | else |
104 | lua_pushfstring(L, "system error %d\n" , error); |
105 | } |
106 | |
107 | static void ll_unloadlib(void *lib) |
108 | { |
109 | FreeLibrary((HINSTANCE)lib); |
110 | } |
111 | |
112 | static void *ll_load(lua_State *L, const char *path, int gl) |
113 | { |
114 | HINSTANCE lib = LoadLibraryA(path); |
115 | if (lib == NULL) pusherror(L); |
116 | UNUSED(gl); |
117 | return lib; |
118 | } |
119 | |
120 | static lua_CFunction ll_sym(lua_State *L, void *lib, const char *sym) |
121 | { |
122 | lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym); |
123 | if (f == NULL) pusherror(L); |
124 | return f; |
125 | } |
126 | |
127 | static const char *ll_bcsym(void *lib, const char *sym) |
128 | { |
129 | if (lib) { |
130 | return (const char *)GetProcAddress((HINSTANCE)lib, sym); |
131 | } else { |
132 | HINSTANCE h = GetModuleHandleA(NULL); |
133 | const char *p = (const char *)GetProcAddress(h, sym); |
134 | if (p == NULL && GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, |
135 | (const char *)ll_bcsym, &h)) |
136 | p = (const char *)GetProcAddress(h, sym); |
137 | return p; |
138 | } |
139 | } |
140 | |
141 | #else |
142 | |
143 | #undef PACKAGE_LIB_FAIL |
144 | #define PACKAGE_LIB_FAIL "absent" |
145 | |
146 | #define DLMSG "dynamic libraries not enabled; no support for target OS" |
147 | |
148 | static void ll_unloadlib(void *lib) |
149 | { |
150 | UNUSED(lib); |
151 | } |
152 | |
153 | static void *ll_load(lua_State *L, const char *path, int gl) |
154 | { |
155 | UNUSED(path); UNUSED(gl); |
156 | lua_pushliteral(L, DLMSG); |
157 | return NULL; |
158 | } |
159 | |
160 | static lua_CFunction ll_sym(lua_State *L, void *lib, const char *sym) |
161 | { |
162 | UNUSED(lib); UNUSED(sym); |
163 | lua_pushliteral(L, DLMSG); |
164 | return NULL; |
165 | } |
166 | |
167 | static const char *ll_bcsym(void *lib, const char *sym) |
168 | { |
169 | UNUSED(lib); UNUSED(sym); |
170 | return NULL; |
171 | } |
172 | |
173 | #endif |
174 | |
175 | /* ------------------------------------------------------------------------ */ |
176 | |
177 | static void **ll_register(lua_State *L, const char *path) |
178 | { |
179 | void **plib; |
180 | lua_pushfstring(L, "LOADLIB: %s" , path); |
181 | lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ |
182 | if (!lua_isnil(L, -1)) { /* is there an entry? */ |
183 | plib = (void **)lua_touserdata(L, -1); |
184 | } else { /* no entry yet; create one */ |
185 | lua_pop(L, 1); |
186 | plib = (void **)lua_newuserdata(L, sizeof(void *)); |
187 | *plib = NULL; |
188 | luaL_getmetatable(L, "_LOADLIB" ); |
189 | lua_setmetatable(L, -2); |
190 | lua_pushfstring(L, "LOADLIB: %s" , path); |
191 | lua_pushvalue(L, -2); |
192 | lua_settable(L, LUA_REGISTRYINDEX); |
193 | } |
194 | return plib; |
195 | } |
196 | |
197 | static const char *mksymname(lua_State *L, const char *modname, |
198 | const char *prefix) |
199 | { |
200 | const char *funcname; |
201 | const char *mark = strchr(modname, *LUA_IGMARK); |
202 | if (mark) modname = mark + 1; |
203 | funcname = luaL_gsub(L, modname, "." , "_" ); |
204 | funcname = lua_pushfstring(L, prefix, funcname); |
205 | lua_remove(L, -2); /* remove 'gsub' result */ |
206 | return funcname; |
207 | } |
208 | |
209 | static int ll_loadfunc(lua_State *L, const char *path, const char *name, int r) |
210 | { |
211 | void **reg = ll_register(L, path); |
212 | if (*reg == NULL) *reg = ll_load(L, path, (*name == '*')); |
213 | if (*reg == NULL) { |
214 | return PACKAGE_ERR_LIB; /* Unable to load library. */ |
215 | } else if (*name == '*') { /* Only load library into global namespace. */ |
216 | lua_pushboolean(L, 1); |
217 | return 0; |
218 | } else { |
219 | const char *sym = r ? name : mksymname(L, name, SYMPREFIX_CF); |
220 | lua_CFunction f = ll_sym(L, *reg, sym); |
221 | if (f) { |
222 | lua_pushcfunction(L, f); |
223 | return 0; |
224 | } |
225 | if (!r) { |
226 | const char *bcdata = ll_bcsym(*reg, mksymname(L, name, SYMPREFIX_BC)); |
227 | lua_pop(L, 1); |
228 | if (bcdata) { |
229 | if (luaL_loadbuffer(L, bcdata, ~(size_t)0, name) != 0) |
230 | return PACKAGE_ERR_LOAD; |
231 | return 0; |
232 | } |
233 | } |
234 | return PACKAGE_ERR_FUNC; /* Unable to find function. */ |
235 | } |
236 | } |
237 | |
238 | static int lj_cf_package_loadlib(lua_State *L) |
239 | { |
240 | const char *path = luaL_checkstring(L, 1); |
241 | const char *init = luaL_checkstring(L, 2); |
242 | int st = ll_loadfunc(L, path, init, 1); |
243 | if (st == 0) { /* no errors? */ |
244 | return 1; /* return the loaded function */ |
245 | } else { /* error; error message is on stack top */ |
246 | lua_pushnil(L); |
247 | lua_insert(L, -2); |
248 | lua_pushstring(L, (st == PACKAGE_ERR_LIB) ? PACKAGE_LIB_FAIL : "init" ); |
249 | return 3; /* return nil, error message, and where */ |
250 | } |
251 | } |
252 | |
253 | static int lj_cf_package_unloadlib(lua_State *L) |
254 | { |
255 | void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB" ); |
256 | if (*lib) ll_unloadlib(*lib); |
257 | *lib = NULL; /* mark library as closed */ |
258 | return 0; |
259 | } |
260 | |
261 | /* ------------------------------------------------------------------------ */ |
262 | |
263 | static int readable(const char *filename) |
264 | { |
265 | FILE *f = fopen(filename, "r" ); /* try to open file */ |
266 | if (f == NULL) return 0; /* open failed */ |
267 | fclose(f); |
268 | return 1; |
269 | } |
270 | |
271 | static const char *pushnexttemplate(lua_State *L, const char *path) |
272 | { |
273 | const char *l; |
274 | while (*path == *LUA_PATHSEP) path++; /* skip separators */ |
275 | if (*path == '\0') return NULL; /* no more templates */ |
276 | l = strchr(path, *LUA_PATHSEP); /* find next separator */ |
277 | if (l == NULL) l = path + strlen(path); |
278 | lua_pushlstring(L, path, (size_t)(l - path)); /* template */ |
279 | return l; |
280 | } |
281 | |
282 | static const char *searchpath (lua_State *L, const char *name, |
283 | const char *path, const char *sep, |
284 | const char *dirsep) |
285 | { |
286 | luaL_Buffer msg; /* to build error message */ |
287 | luaL_buffinit(L, &msg); |
288 | if (*sep != '\0') /* non-empty separator? */ |
289 | name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ |
290 | while ((path = pushnexttemplate(L, path)) != NULL) { |
291 | const char *filename = luaL_gsub(L, lua_tostring(L, -1), |
292 | LUA_PATH_MARK, name); |
293 | lua_remove(L, -2); /* remove path template */ |
294 | if (readable(filename)) /* does file exist and is readable? */ |
295 | return filename; /* return that file name */ |
296 | lua_pushfstring(L, "\n\tno file " LUA_QS, filename); |
297 | lua_remove(L, -2); /* remove file name */ |
298 | luaL_addvalue(&msg); /* concatenate error msg. entry */ |
299 | } |
300 | luaL_pushresult(&msg); /* create error message */ |
301 | return NULL; /* not found */ |
302 | } |
303 | |
304 | static int lj_cf_package_searchpath(lua_State *L) |
305 | { |
306 | const char *f = searchpath(L, luaL_checkstring(L, 1), |
307 | luaL_checkstring(L, 2), |
308 | luaL_optstring(L, 3, "." ), |
309 | luaL_optstring(L, 4, LUA_DIRSEP)); |
310 | if (f != NULL) { |
311 | return 1; |
312 | } else { /* error message is on top of the stack */ |
313 | lua_pushnil(L); |
314 | lua_insert(L, -2); |
315 | return 2; /* return nil + error message */ |
316 | } |
317 | } |
318 | |
319 | static const char *findfile(lua_State *L, const char *name, |
320 | const char *pname) |
321 | { |
322 | const char *path; |
323 | lua_getfield(L, LUA_ENVIRONINDEX, pname); |
324 | path = lua_tostring(L, -1); |
325 | if (path == NULL) |
326 | luaL_error(L, LUA_QL("package.%s" ) " must be a string" , pname); |
327 | return searchpath(L, name, path, "." , LUA_DIRSEP); |
328 | } |
329 | |
330 | static void loaderror(lua_State *L, const char *filename) |
331 | { |
332 | luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s" , |
333 | lua_tostring(L, 1), filename, lua_tostring(L, -1)); |
334 | } |
335 | |
336 | static int lj_cf_package_loader_lua(lua_State *L) |
337 | { |
338 | const char *filename; |
339 | const char *name = luaL_checkstring(L, 1); |
340 | filename = findfile(L, name, "path" ); |
341 | if (filename == NULL) return 1; /* library not found in this path */ |
342 | if (luaL_loadfile(L, filename) != 0) |
343 | loaderror(L, filename); |
344 | return 1; /* library loaded successfully */ |
345 | } |
346 | |
347 | static int lj_cf_package_loader_c(lua_State *L) |
348 | { |
349 | const char *name = luaL_checkstring(L, 1); |
350 | const char *filename = findfile(L, name, "cpath" ); |
351 | if (filename == NULL) return 1; /* library not found in this path */ |
352 | if (ll_loadfunc(L, filename, name, 0) != 0) |
353 | loaderror(L, filename); |
354 | return 1; /* library loaded successfully */ |
355 | } |
356 | |
357 | static int lj_cf_package_loader_croot(lua_State *L) |
358 | { |
359 | const char *filename; |
360 | const char *name = luaL_checkstring(L, 1); |
361 | const char *p = strchr(name, '.'); |
362 | int st; |
363 | if (p == NULL) return 0; /* is root */ |
364 | lua_pushlstring(L, name, (size_t)(p - name)); |
365 | filename = findfile(L, lua_tostring(L, -1), "cpath" ); |
366 | if (filename == NULL) return 1; /* root not found */ |
367 | if ((st = ll_loadfunc(L, filename, name, 0)) != 0) { |
368 | if (st != PACKAGE_ERR_FUNC) loaderror(L, filename); /* real error */ |
369 | lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, |
370 | name, filename); |
371 | return 1; /* function not found */ |
372 | } |
373 | return 1; |
374 | } |
375 | |
376 | static int lj_cf_package_loader_preload(lua_State *L) |
377 | { |
378 | const char *name = luaL_checkstring(L, 1); |
379 | lua_getfield(L, LUA_ENVIRONINDEX, "preload" ); |
380 | if (!lua_istable(L, -1)) |
381 | luaL_error(L, LUA_QL("package.preload" ) " must be a table" ); |
382 | lua_getfield(L, -1, name); |
383 | if (lua_isnil(L, -1)) { /* Not found? */ |
384 | const char *bcname = mksymname(L, name, SYMPREFIX_BC); |
385 | const char *bcdata = ll_bcsym(NULL, bcname); |
386 | if (bcdata == NULL || luaL_loadbuffer(L, bcdata, ~(size_t)0, name) != 0) |
387 | lua_pushfstring(L, "\n\tno field package.preload['%s']" , name); |
388 | } |
389 | return 1; |
390 | } |
391 | |
392 | /* ------------------------------------------------------------------------ */ |
393 | |
394 | static const int sentinel_ = 0; |
395 | #define sentinel ((void *)&sentinel_) |
396 | |
397 | static int lj_cf_package_require(lua_State *L) |
398 | { |
399 | const char *name = luaL_checkstring(L, 1); |
400 | int i; |
401 | lua_settop(L, 1); /* _LOADED table will be at index 2 */ |
402 | lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED" ); |
403 | lua_getfield(L, 2, name); |
404 | if (lua_toboolean(L, -1)) { /* is it there? */ |
405 | if (lua_touserdata(L, -1) == sentinel) /* check loops */ |
406 | luaL_error(L, "loop or previous error loading module " LUA_QS, name); |
407 | return 1; /* package is already loaded */ |
408 | } |
409 | /* else must load it; iterate over available loaders */ |
410 | lua_getfield(L, LUA_ENVIRONINDEX, "loaders" ); |
411 | if (!lua_istable(L, -1)) |
412 | luaL_error(L, LUA_QL("package.loaders" ) " must be a table" ); |
413 | lua_pushliteral(L, "" ); /* error message accumulator */ |
414 | for (i = 1; ; i++) { |
415 | lua_rawgeti(L, -2, i); /* get a loader */ |
416 | if (lua_isnil(L, -1)) |
417 | luaL_error(L, "module " LUA_QS " not found:%s" , |
418 | name, lua_tostring(L, -2)); |
419 | lua_pushstring(L, name); |
420 | lua_call(L, 1, 1); /* call it */ |
421 | if (lua_isfunction(L, -1)) /* did it find module? */ |
422 | break; /* module loaded successfully */ |
423 | else if (lua_isstring(L, -1)) /* loader returned error message? */ |
424 | lua_concat(L, 2); /* accumulate it */ |
425 | else |
426 | lua_pop(L, 1); |
427 | } |
428 | lua_pushlightuserdata(L, sentinel); |
429 | lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ |
430 | lua_pushstring(L, name); /* pass name as argument to module */ |
431 | lua_call(L, 1, 1); /* run loaded module */ |
432 | if (!lua_isnil(L, -1)) /* non-nil return? */ |
433 | lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ |
434 | lua_getfield(L, 2, name); |
435 | if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */ |
436 | lua_pushboolean(L, 1); /* use true as result */ |
437 | lua_pushvalue(L, -1); /* extra copy to be returned */ |
438 | lua_setfield(L, 2, name); /* _LOADED[name] = true */ |
439 | } |
440 | lj_lib_checkfpu(L); |
441 | return 1; |
442 | } |
443 | |
444 | /* ------------------------------------------------------------------------ */ |
445 | |
446 | static void setfenv(lua_State *L) |
447 | { |
448 | lua_Debug ar; |
449 | if (lua_getstack(L, 1, &ar) == 0 || |
450 | lua_getinfo(L, "f" , &ar) == 0 || /* get calling function */ |
451 | lua_iscfunction(L, -1)) |
452 | luaL_error(L, LUA_QL("module" ) " not called from a Lua function" ); |
453 | lua_pushvalue(L, -2); |
454 | lua_setfenv(L, -2); |
455 | lua_pop(L, 1); |
456 | } |
457 | |
458 | static void dooptions(lua_State *L, int n) |
459 | { |
460 | int i; |
461 | for (i = 2; i <= n; i++) { |
462 | lua_pushvalue(L, i); /* get option (a function) */ |
463 | lua_pushvalue(L, -2); /* module */ |
464 | lua_call(L, 1, 0); |
465 | } |
466 | } |
467 | |
468 | static void modinit(lua_State *L, const char *modname) |
469 | { |
470 | const char *dot; |
471 | lua_pushvalue(L, -1); |
472 | lua_setfield(L, -2, "_M" ); /* module._M = module */ |
473 | lua_pushstring(L, modname); |
474 | lua_setfield(L, -2, "_NAME" ); |
475 | dot = strrchr(modname, '.'); /* look for last dot in module name */ |
476 | if (dot == NULL) dot = modname; else dot++; |
477 | /* set _PACKAGE as package name (full module name minus last part) */ |
478 | lua_pushlstring(L, modname, (size_t)(dot - modname)); |
479 | lua_setfield(L, -2, "_PACKAGE" ); |
480 | } |
481 | |
482 | static int lj_cf_package_module(lua_State *L) |
483 | { |
484 | const char *modname = luaL_checkstring(L, 1); |
485 | int loaded = lua_gettop(L) + 1; /* index of _LOADED table */ |
486 | lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED" ); |
487 | lua_getfield(L, loaded, modname); /* get _LOADED[modname] */ |
488 | if (!lua_istable(L, -1)) { /* not found? */ |
489 | lua_pop(L, 1); /* remove previous result */ |
490 | /* try global variable (and create one if it does not exist) */ |
491 | if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL) |
492 | lj_err_callerv(L, LJ_ERR_BADMODN, modname); |
493 | lua_pushvalue(L, -1); |
494 | lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */ |
495 | } |
496 | /* check whether table already has a _NAME field */ |
497 | lua_getfield(L, -1, "_NAME" ); |
498 | if (!lua_isnil(L, -1)) { /* is table an initialized module? */ |
499 | lua_pop(L, 1); |
500 | } else { /* no; initialize it */ |
501 | lua_pop(L, 1); |
502 | modinit(L, modname); |
503 | } |
504 | lua_pushvalue(L, -1); |
505 | setfenv(L); |
506 | dooptions(L, loaded - 1); |
507 | return 0; |
508 | } |
509 | |
510 | static int lj_cf_package_seeall(lua_State *L) |
511 | { |
512 | luaL_checktype(L, 1, LUA_TTABLE); |
513 | if (!lua_getmetatable(L, 1)) { |
514 | lua_createtable(L, 0, 1); /* create new metatable */ |
515 | lua_pushvalue(L, -1); |
516 | lua_setmetatable(L, 1); |
517 | } |
518 | lua_pushvalue(L, LUA_GLOBALSINDEX); |
519 | lua_setfield(L, -2, "__index" ); /* mt.__index = _G */ |
520 | return 0; |
521 | } |
522 | |
523 | /* ------------------------------------------------------------------------ */ |
524 | |
525 | #define AUXMARK "\1" |
526 | |
527 | static void setpath(lua_State *L, const char *fieldname, const char *envname, |
528 | const char *def, int noenv) |
529 | { |
530 | #if LJ_TARGET_CONSOLE |
531 | const char *path = NULL; |
532 | UNUSED(envname); |
533 | #else |
534 | const char *path = getenv(envname); |
535 | #endif |
536 | if (path == NULL || noenv) { |
537 | lua_pushstring(L, def); |
538 | } else { |
539 | path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP, |
540 | LUA_PATHSEP AUXMARK LUA_PATHSEP); |
541 | luaL_gsub(L, path, AUXMARK, def); |
542 | lua_remove(L, -2); |
543 | } |
544 | setprogdir(L); |
545 | lua_setfield(L, -2, fieldname); |
546 | } |
547 | |
548 | static const luaL_Reg package_lib[] = { |
549 | { "loadlib" , lj_cf_package_loadlib }, |
550 | { "searchpath" , lj_cf_package_searchpath }, |
551 | { "seeall" , lj_cf_package_seeall }, |
552 | { NULL, NULL } |
553 | }; |
554 | |
555 | static const luaL_Reg package_global[] = { |
556 | { "module" , lj_cf_package_module }, |
557 | { "require" , lj_cf_package_require }, |
558 | { NULL, NULL } |
559 | }; |
560 | |
561 | static const lua_CFunction package_loaders[] = |
562 | { |
563 | lj_cf_package_loader_preload, |
564 | lj_cf_package_loader_lua, |
565 | lj_cf_package_loader_c, |
566 | lj_cf_package_loader_croot, |
567 | NULL |
568 | }; |
569 | |
570 | LUALIB_API int luaopen_package(lua_State *L) |
571 | { |
572 | int i; |
573 | int noenv; |
574 | luaL_newmetatable(L, "_LOADLIB" ); |
575 | lj_lib_pushcf(L, lj_cf_package_unloadlib, 1); |
576 | lua_setfield(L, -2, "__gc" ); |
577 | luaL_register(L, LUA_LOADLIBNAME, package_lib); |
578 | lua_pushvalue(L, -1); |
579 | lua_replace(L, LUA_ENVIRONINDEX); |
580 | lua_createtable(L, sizeof(package_loaders)/sizeof(package_loaders[0])-1, 0); |
581 | for (i = 0; package_loaders[i] != NULL; i++) { |
582 | lj_lib_pushcf(L, package_loaders[i], 1); |
583 | lua_rawseti(L, -2, i+1); |
584 | } |
585 | lua_setfield(L, -2, "loaders" ); |
586 | lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV" ); |
587 | noenv = lua_toboolean(L, -1); |
588 | lua_pop(L, 1); |
589 | setpath(L, "path" , LUA_PATH, LUA_PATH_DEFAULT, noenv); |
590 | setpath(L, "cpath" , LUA_CPATH, LUA_CPATH_DEFAULT, noenv); |
591 | lua_pushliteral(L, LUA_PATH_CONFIG); |
592 | lua_setfield(L, -2, "config" ); |
593 | luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED" , 16); |
594 | lua_setfield(L, -2, "loaded" ); |
595 | luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD" , 4); |
596 | lua_setfield(L, -2, "preload" ); |
597 | lua_pushvalue(L, LUA_GLOBALSINDEX); |
598 | luaL_register(L, NULL, package_global); |
599 | lua_pop(L, 1); |
600 | return 1; |
601 | } |
602 | |
603 | |