Mercurial
comparison third_party/luajit/src/lib_package.c @ 186:8cf4ec5e2191 hg-web
Fixed merge conflict.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Fri, 23 Jan 2026 22:38:59 -0800 |
| parents | 94705b5986b3 |
| children |
comparison
equal
deleted
inserted
replaced
| 176:fed99fc04e12 | 186:8cf4ec5e2191 |
|---|---|
| 1 /* | |
| 2 ** Package library. | |
| 3 ** Copyright (C) 2005-2023 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) && !defined(NO_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 |