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