1*8e3e3a7aSWarner Losh /* 2*8e3e3a7aSWarner Losh ** $Id: loadlib.c,v 1.130 2017/01/12 17:14:26 roberto Exp $ 3*8e3e3a7aSWarner Losh ** Dynamic library loader for Lua 4*8e3e3a7aSWarner Losh ** See Copyright Notice in lua.h 5*8e3e3a7aSWarner Losh ** 6*8e3e3a7aSWarner Losh ** This module contains an implementation of loadlib for Unix systems 7*8e3e3a7aSWarner Losh ** that have dlfcn, an implementation for Windows, and a stub for other 8*8e3e3a7aSWarner Losh ** systems. 9*8e3e3a7aSWarner Losh */ 10*8e3e3a7aSWarner Losh 11*8e3e3a7aSWarner Losh #define loadlib_c 12*8e3e3a7aSWarner Losh #define LUA_LIB 13*8e3e3a7aSWarner Losh 14*8e3e3a7aSWarner Losh #include "lprefix.h" 15*8e3e3a7aSWarner Losh 16*8e3e3a7aSWarner Losh 17*8e3e3a7aSWarner Losh #include <stdio.h> 18*8e3e3a7aSWarner Losh #include <stdlib.h> 19*8e3e3a7aSWarner Losh #include <string.h> 20*8e3e3a7aSWarner Losh 21*8e3e3a7aSWarner Losh #include "lua.h" 22*8e3e3a7aSWarner Losh 23*8e3e3a7aSWarner Losh #include "lauxlib.h" 24*8e3e3a7aSWarner Losh #include "lualib.h" 25*8e3e3a7aSWarner Losh 26*8e3e3a7aSWarner Losh 27*8e3e3a7aSWarner Losh /* 28*8e3e3a7aSWarner Losh ** LUA_IGMARK is a mark to ignore all before it when building the 29*8e3e3a7aSWarner Losh ** luaopen_ function name. 30*8e3e3a7aSWarner Losh */ 31*8e3e3a7aSWarner Losh #if !defined (LUA_IGMARK) 32*8e3e3a7aSWarner Losh #define LUA_IGMARK "-" 33*8e3e3a7aSWarner Losh #endif 34*8e3e3a7aSWarner Losh 35*8e3e3a7aSWarner Losh 36*8e3e3a7aSWarner Losh /* 37*8e3e3a7aSWarner Losh ** LUA_CSUBSEP is the character that replaces dots in submodule names 38*8e3e3a7aSWarner Losh ** when searching for a C loader. 39*8e3e3a7aSWarner Losh ** LUA_LSUBSEP is the character that replaces dots in submodule names 40*8e3e3a7aSWarner Losh ** when searching for a Lua loader. 41*8e3e3a7aSWarner Losh */ 42*8e3e3a7aSWarner Losh #if !defined(LUA_CSUBSEP) 43*8e3e3a7aSWarner Losh #define LUA_CSUBSEP LUA_DIRSEP 44*8e3e3a7aSWarner Losh #endif 45*8e3e3a7aSWarner Losh 46*8e3e3a7aSWarner Losh #if !defined(LUA_LSUBSEP) 47*8e3e3a7aSWarner Losh #define LUA_LSUBSEP LUA_DIRSEP 48*8e3e3a7aSWarner Losh #endif 49*8e3e3a7aSWarner Losh 50*8e3e3a7aSWarner Losh 51*8e3e3a7aSWarner Losh /* prefix for open functions in C libraries */ 52*8e3e3a7aSWarner Losh #define LUA_POF "luaopen_" 53*8e3e3a7aSWarner Losh 54*8e3e3a7aSWarner Losh /* separator for open functions in C libraries */ 55*8e3e3a7aSWarner Losh #define LUA_OFSEP "_" 56*8e3e3a7aSWarner Losh 57*8e3e3a7aSWarner Losh 58*8e3e3a7aSWarner Losh /* 59*8e3e3a7aSWarner Losh ** unique key for table in the registry that keeps handles 60*8e3e3a7aSWarner Losh ** for all loaded C libraries 61*8e3e3a7aSWarner Losh */ 62*8e3e3a7aSWarner Losh static const int CLIBS = 0; 63*8e3e3a7aSWarner Losh 64*8e3e3a7aSWarner Losh #define LIB_FAIL "open" 65*8e3e3a7aSWarner Losh 66*8e3e3a7aSWarner Losh 67*8e3e3a7aSWarner Losh #define setprogdir(L) ((void)0) 68*8e3e3a7aSWarner Losh 69*8e3e3a7aSWarner Losh 70*8e3e3a7aSWarner Losh /* 71*8e3e3a7aSWarner Losh ** system-dependent functions 72*8e3e3a7aSWarner Losh */ 73*8e3e3a7aSWarner Losh 74*8e3e3a7aSWarner Losh /* 75*8e3e3a7aSWarner Losh ** unload library 'lib' 76*8e3e3a7aSWarner Losh */ 77*8e3e3a7aSWarner Losh static void lsys_unloadlib (void *lib); 78*8e3e3a7aSWarner Losh 79*8e3e3a7aSWarner Losh /* 80*8e3e3a7aSWarner Losh ** load C library in file 'path'. If 'seeglb', load with all names in 81*8e3e3a7aSWarner Losh ** the library global. 82*8e3e3a7aSWarner Losh ** Returns the library; in case of error, returns NULL plus an 83*8e3e3a7aSWarner Losh ** error string in the stack. 84*8e3e3a7aSWarner Losh */ 85*8e3e3a7aSWarner Losh static void *lsys_load (lua_State *L, const char *path, int seeglb); 86*8e3e3a7aSWarner Losh 87*8e3e3a7aSWarner Losh /* 88*8e3e3a7aSWarner Losh ** Try to find a function named 'sym' in library 'lib'. 89*8e3e3a7aSWarner Losh ** Returns the function; in case of error, returns NULL plus an 90*8e3e3a7aSWarner Losh ** error string in the stack. 91*8e3e3a7aSWarner Losh */ 92*8e3e3a7aSWarner Losh static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym); 93*8e3e3a7aSWarner Losh 94*8e3e3a7aSWarner Losh 95*8e3e3a7aSWarner Losh 96*8e3e3a7aSWarner Losh 97*8e3e3a7aSWarner Losh #if defined(LUA_USE_DLOPEN) /* { */ 98*8e3e3a7aSWarner Losh /* 99*8e3e3a7aSWarner Losh ** {======================================================================== 100*8e3e3a7aSWarner Losh ** This is an implementation of loadlib based on the dlfcn interface. 101*8e3e3a7aSWarner Losh ** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, 102*8e3e3a7aSWarner Losh ** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least 103*8e3e3a7aSWarner Losh ** as an emulation layer on top of native functions. 104*8e3e3a7aSWarner Losh ** ========================================================================= 105*8e3e3a7aSWarner Losh */ 106*8e3e3a7aSWarner Losh 107*8e3e3a7aSWarner Losh #include <dlfcn.h> 108*8e3e3a7aSWarner Losh 109*8e3e3a7aSWarner Losh /* 110*8e3e3a7aSWarner Losh ** Macro to convert pointer-to-void* to pointer-to-function. This cast 111*8e3e3a7aSWarner Losh ** is undefined according to ISO C, but POSIX assumes that it works. 112*8e3e3a7aSWarner Losh ** (The '__extension__' in gnu compilers is only to avoid warnings.) 113*8e3e3a7aSWarner Losh */ 114*8e3e3a7aSWarner Losh #if defined(__GNUC__) 115*8e3e3a7aSWarner Losh #define cast_func(p) (__extension__ (lua_CFunction)(p)) 116*8e3e3a7aSWarner Losh #else 117*8e3e3a7aSWarner Losh #define cast_func(p) ((lua_CFunction)(p)) 118*8e3e3a7aSWarner Losh #endif 119*8e3e3a7aSWarner Losh 120*8e3e3a7aSWarner Losh 121*8e3e3a7aSWarner Losh static void lsys_unloadlib (void *lib) { 122*8e3e3a7aSWarner Losh dlclose(lib); 123*8e3e3a7aSWarner Losh } 124*8e3e3a7aSWarner Losh 125*8e3e3a7aSWarner Losh 126*8e3e3a7aSWarner Losh static void *lsys_load (lua_State *L, const char *path, int seeglb) { 127*8e3e3a7aSWarner Losh void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); 128*8e3e3a7aSWarner Losh if (lib == NULL) lua_pushstring(L, dlerror()); 129*8e3e3a7aSWarner Losh return lib; 130*8e3e3a7aSWarner Losh } 131*8e3e3a7aSWarner Losh 132*8e3e3a7aSWarner Losh 133*8e3e3a7aSWarner Losh static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { 134*8e3e3a7aSWarner Losh lua_CFunction f = cast_func(dlsym(lib, sym)); 135*8e3e3a7aSWarner Losh if (f == NULL) lua_pushstring(L, dlerror()); 136*8e3e3a7aSWarner Losh return f; 137*8e3e3a7aSWarner Losh } 138*8e3e3a7aSWarner Losh 139*8e3e3a7aSWarner Losh /* }====================================================== */ 140*8e3e3a7aSWarner Losh 141*8e3e3a7aSWarner Losh 142*8e3e3a7aSWarner Losh 143*8e3e3a7aSWarner Losh #elif defined(LUA_DL_DLL) /* }{ */ 144*8e3e3a7aSWarner Losh /* 145*8e3e3a7aSWarner Losh ** {====================================================================== 146*8e3e3a7aSWarner Losh ** This is an implementation of loadlib for Windows using native functions. 147*8e3e3a7aSWarner Losh ** ======================================================================= 148*8e3e3a7aSWarner Losh */ 149*8e3e3a7aSWarner Losh 150*8e3e3a7aSWarner Losh #include <windows.h> 151*8e3e3a7aSWarner Losh 152*8e3e3a7aSWarner Losh 153*8e3e3a7aSWarner Losh /* 154*8e3e3a7aSWarner Losh ** optional flags for LoadLibraryEx 155*8e3e3a7aSWarner Losh */ 156*8e3e3a7aSWarner Losh #if !defined(LUA_LLE_FLAGS) 157*8e3e3a7aSWarner Losh #define LUA_LLE_FLAGS 0 158*8e3e3a7aSWarner Losh #endif 159*8e3e3a7aSWarner Losh 160*8e3e3a7aSWarner Losh 161*8e3e3a7aSWarner Losh #undef setprogdir 162*8e3e3a7aSWarner Losh 163*8e3e3a7aSWarner Losh 164*8e3e3a7aSWarner Losh /* 165*8e3e3a7aSWarner Losh ** Replace in the path (on the top of the stack) any occurrence 166*8e3e3a7aSWarner Losh ** of LUA_EXEC_DIR with the executable's path. 167*8e3e3a7aSWarner Losh */ 168*8e3e3a7aSWarner Losh static void setprogdir (lua_State *L) { 169*8e3e3a7aSWarner Losh char buff[MAX_PATH + 1]; 170*8e3e3a7aSWarner Losh char *lb; 171*8e3e3a7aSWarner Losh DWORD nsize = sizeof(buff)/sizeof(char); 172*8e3e3a7aSWarner Losh DWORD n = GetModuleFileNameA(NULL, buff, nsize); /* get exec. name */ 173*8e3e3a7aSWarner Losh if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) 174*8e3e3a7aSWarner Losh luaL_error(L, "unable to get ModuleFileName"); 175*8e3e3a7aSWarner Losh else { 176*8e3e3a7aSWarner Losh *lb = '\0'; /* cut name on the last '\\' to get the path */ 177*8e3e3a7aSWarner Losh luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff); 178*8e3e3a7aSWarner Losh lua_remove(L, -2); /* remove original string */ 179*8e3e3a7aSWarner Losh } 180*8e3e3a7aSWarner Losh } 181*8e3e3a7aSWarner Losh 182*8e3e3a7aSWarner Losh 183*8e3e3a7aSWarner Losh 184*8e3e3a7aSWarner Losh 185*8e3e3a7aSWarner Losh static void pusherror (lua_State *L) { 186*8e3e3a7aSWarner Losh int error = GetLastError(); 187*8e3e3a7aSWarner Losh char buffer[128]; 188*8e3e3a7aSWarner Losh if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, 189*8e3e3a7aSWarner Losh NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL)) 190*8e3e3a7aSWarner Losh lua_pushstring(L, buffer); 191*8e3e3a7aSWarner Losh else 192*8e3e3a7aSWarner Losh lua_pushfstring(L, "system error %d\n", error); 193*8e3e3a7aSWarner Losh } 194*8e3e3a7aSWarner Losh 195*8e3e3a7aSWarner Losh static void lsys_unloadlib (void *lib) { 196*8e3e3a7aSWarner Losh FreeLibrary((HMODULE)lib); 197*8e3e3a7aSWarner Losh } 198*8e3e3a7aSWarner Losh 199*8e3e3a7aSWarner Losh 200*8e3e3a7aSWarner Losh static void *lsys_load (lua_State *L, const char *path, int seeglb) { 201*8e3e3a7aSWarner Losh HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); 202*8e3e3a7aSWarner Losh (void)(seeglb); /* not used: symbols are 'global' by default */ 203*8e3e3a7aSWarner Losh if (lib == NULL) pusherror(L); 204*8e3e3a7aSWarner Losh return lib; 205*8e3e3a7aSWarner Losh } 206*8e3e3a7aSWarner Losh 207*8e3e3a7aSWarner Losh 208*8e3e3a7aSWarner Losh static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { 209*8e3e3a7aSWarner Losh lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym); 210*8e3e3a7aSWarner Losh if (f == NULL) pusherror(L); 211*8e3e3a7aSWarner Losh return f; 212*8e3e3a7aSWarner Losh } 213*8e3e3a7aSWarner Losh 214*8e3e3a7aSWarner Losh /* }====================================================== */ 215*8e3e3a7aSWarner Losh 216*8e3e3a7aSWarner Losh 217*8e3e3a7aSWarner Losh #else /* }{ */ 218*8e3e3a7aSWarner Losh /* 219*8e3e3a7aSWarner Losh ** {====================================================== 220*8e3e3a7aSWarner Losh ** Fallback for other systems 221*8e3e3a7aSWarner Losh ** ======================================================= 222*8e3e3a7aSWarner Losh */ 223*8e3e3a7aSWarner Losh 224*8e3e3a7aSWarner Losh #undef LIB_FAIL 225*8e3e3a7aSWarner Losh #define LIB_FAIL "absent" 226*8e3e3a7aSWarner Losh 227*8e3e3a7aSWarner Losh 228*8e3e3a7aSWarner Losh #define DLMSG "dynamic libraries not enabled; check your Lua installation" 229*8e3e3a7aSWarner Losh 230*8e3e3a7aSWarner Losh 231*8e3e3a7aSWarner Losh static void lsys_unloadlib (void *lib) { 232*8e3e3a7aSWarner Losh (void)(lib); /* not used */ 233*8e3e3a7aSWarner Losh } 234*8e3e3a7aSWarner Losh 235*8e3e3a7aSWarner Losh 236*8e3e3a7aSWarner Losh static void *lsys_load (lua_State *L, const char *path, int seeglb) { 237*8e3e3a7aSWarner Losh (void)(path); (void)(seeglb); /* not used */ 238*8e3e3a7aSWarner Losh lua_pushliteral(L, DLMSG); 239*8e3e3a7aSWarner Losh return NULL; 240*8e3e3a7aSWarner Losh } 241*8e3e3a7aSWarner Losh 242*8e3e3a7aSWarner Losh 243*8e3e3a7aSWarner Losh static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { 244*8e3e3a7aSWarner Losh (void)(lib); (void)(sym); /* not used */ 245*8e3e3a7aSWarner Losh lua_pushliteral(L, DLMSG); 246*8e3e3a7aSWarner Losh return NULL; 247*8e3e3a7aSWarner Losh } 248*8e3e3a7aSWarner Losh 249*8e3e3a7aSWarner Losh /* }====================================================== */ 250*8e3e3a7aSWarner Losh #endif /* } */ 251*8e3e3a7aSWarner Losh 252*8e3e3a7aSWarner Losh 253*8e3e3a7aSWarner Losh /* 254*8e3e3a7aSWarner Losh ** {================================================================== 255*8e3e3a7aSWarner Losh ** Set Paths 256*8e3e3a7aSWarner Losh ** =================================================================== 257*8e3e3a7aSWarner Losh */ 258*8e3e3a7aSWarner Losh 259*8e3e3a7aSWarner Losh /* 260*8e3e3a7aSWarner Losh ** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment 261*8e3e3a7aSWarner Losh ** variables that Lua check to set its paths. 262*8e3e3a7aSWarner Losh */ 263*8e3e3a7aSWarner Losh #if !defined(LUA_PATH_VAR) 264*8e3e3a7aSWarner Losh #define LUA_PATH_VAR "LUA_PATH" 265*8e3e3a7aSWarner Losh #endif 266*8e3e3a7aSWarner Losh 267*8e3e3a7aSWarner Losh #if !defined(LUA_CPATH_VAR) 268*8e3e3a7aSWarner Losh #define LUA_CPATH_VAR "LUA_CPATH" 269*8e3e3a7aSWarner Losh #endif 270*8e3e3a7aSWarner Losh 271*8e3e3a7aSWarner Losh 272*8e3e3a7aSWarner Losh #define AUXMARK "\1" /* auxiliary mark */ 273*8e3e3a7aSWarner Losh 274*8e3e3a7aSWarner Losh 275*8e3e3a7aSWarner Losh /* 276*8e3e3a7aSWarner Losh ** return registry.LUA_NOENV as a boolean 277*8e3e3a7aSWarner Losh */ 278*8e3e3a7aSWarner Losh static int noenv (lua_State *L) { 279*8e3e3a7aSWarner Losh int b; 280*8e3e3a7aSWarner Losh lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); 281*8e3e3a7aSWarner Losh b = lua_toboolean(L, -1); 282*8e3e3a7aSWarner Losh lua_pop(L, 1); /* remove value */ 283*8e3e3a7aSWarner Losh return b; 284*8e3e3a7aSWarner Losh } 285*8e3e3a7aSWarner Losh 286*8e3e3a7aSWarner Losh 287*8e3e3a7aSWarner Losh /* 288*8e3e3a7aSWarner Losh ** Set a path 289*8e3e3a7aSWarner Losh */ 290*8e3e3a7aSWarner Losh static void setpath (lua_State *L, const char *fieldname, 291*8e3e3a7aSWarner Losh const char *envname, 292*8e3e3a7aSWarner Losh const char *dft) { 293*8e3e3a7aSWarner Losh const char *nver = lua_pushfstring(L, "%s%s", envname, LUA_VERSUFFIX); 294*8e3e3a7aSWarner Losh const char *path = getenv(nver); /* use versioned name */ 295*8e3e3a7aSWarner Losh if (path == NULL) /* no environment variable? */ 296*8e3e3a7aSWarner Losh path = getenv(envname); /* try unversioned name */ 297*8e3e3a7aSWarner Losh if (path == NULL || noenv(L)) /* no environment variable? */ 298*8e3e3a7aSWarner Losh lua_pushstring(L, dft); /* use default */ 299*8e3e3a7aSWarner Losh else { 300*8e3e3a7aSWarner Losh /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ 301*8e3e3a7aSWarner Losh path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP, 302*8e3e3a7aSWarner Losh LUA_PATH_SEP AUXMARK LUA_PATH_SEP); 303*8e3e3a7aSWarner Losh luaL_gsub(L, path, AUXMARK, dft); 304*8e3e3a7aSWarner Losh lua_remove(L, -2); /* remove result from 1st 'gsub' */ 305*8e3e3a7aSWarner Losh } 306*8e3e3a7aSWarner Losh setprogdir(L); 307*8e3e3a7aSWarner Losh lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */ 308*8e3e3a7aSWarner Losh lua_pop(L, 1); /* pop versioned variable name */ 309*8e3e3a7aSWarner Losh } 310*8e3e3a7aSWarner Losh 311*8e3e3a7aSWarner Losh /* }================================================================== */ 312*8e3e3a7aSWarner Losh 313*8e3e3a7aSWarner Losh 314*8e3e3a7aSWarner Losh /* 315*8e3e3a7aSWarner Losh ** return registry.CLIBS[path] 316*8e3e3a7aSWarner Losh */ 317*8e3e3a7aSWarner Losh static void *checkclib (lua_State *L, const char *path) { 318*8e3e3a7aSWarner Losh void *plib; 319*8e3e3a7aSWarner Losh lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); 320*8e3e3a7aSWarner Losh lua_getfield(L, -1, path); 321*8e3e3a7aSWarner Losh plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ 322*8e3e3a7aSWarner Losh lua_pop(L, 2); /* pop CLIBS table and 'plib' */ 323*8e3e3a7aSWarner Losh return plib; 324*8e3e3a7aSWarner Losh } 325*8e3e3a7aSWarner Losh 326*8e3e3a7aSWarner Losh 327*8e3e3a7aSWarner Losh /* 328*8e3e3a7aSWarner Losh ** registry.CLIBS[path] = plib -- for queries 329*8e3e3a7aSWarner Losh ** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries 330*8e3e3a7aSWarner Losh */ 331*8e3e3a7aSWarner Losh static void addtoclib (lua_State *L, const char *path, void *plib) { 332*8e3e3a7aSWarner Losh lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); 333*8e3e3a7aSWarner Losh lua_pushlightuserdata(L, plib); 334*8e3e3a7aSWarner Losh lua_pushvalue(L, -1); 335*8e3e3a7aSWarner Losh lua_setfield(L, -3, path); /* CLIBS[path] = plib */ 336*8e3e3a7aSWarner Losh lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ 337*8e3e3a7aSWarner Losh lua_pop(L, 1); /* pop CLIBS table */ 338*8e3e3a7aSWarner Losh } 339*8e3e3a7aSWarner Losh 340*8e3e3a7aSWarner Losh 341*8e3e3a7aSWarner Losh /* 342*8e3e3a7aSWarner Losh ** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib 343*8e3e3a7aSWarner Losh ** handles in list CLIBS 344*8e3e3a7aSWarner Losh */ 345*8e3e3a7aSWarner Losh static int gctm (lua_State *L) { 346*8e3e3a7aSWarner Losh lua_Integer n = luaL_len(L, 1); 347*8e3e3a7aSWarner Losh for (; n >= 1; n--) { /* for each handle, in reverse order */ 348*8e3e3a7aSWarner Losh lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ 349*8e3e3a7aSWarner Losh lsys_unloadlib(lua_touserdata(L, -1)); 350*8e3e3a7aSWarner Losh lua_pop(L, 1); /* pop handle */ 351*8e3e3a7aSWarner Losh } 352*8e3e3a7aSWarner Losh return 0; 353*8e3e3a7aSWarner Losh } 354*8e3e3a7aSWarner Losh 355*8e3e3a7aSWarner Losh 356*8e3e3a7aSWarner Losh 357*8e3e3a7aSWarner Losh /* error codes for 'lookforfunc' */ 358*8e3e3a7aSWarner Losh #define ERRLIB 1 359*8e3e3a7aSWarner Losh #define ERRFUNC 2 360*8e3e3a7aSWarner Losh 361*8e3e3a7aSWarner Losh /* 362*8e3e3a7aSWarner Losh ** Look for a C function named 'sym' in a dynamically loaded library 363*8e3e3a7aSWarner Losh ** 'path'. 364*8e3e3a7aSWarner Losh ** First, check whether the library is already loaded; if not, try 365*8e3e3a7aSWarner Losh ** to load it. 366*8e3e3a7aSWarner Losh ** Then, if 'sym' is '*', return true (as library has been loaded). 367*8e3e3a7aSWarner Losh ** Otherwise, look for symbol 'sym' in the library and push a 368*8e3e3a7aSWarner Losh ** C function with that symbol. 369*8e3e3a7aSWarner Losh ** Return 0 and 'true' or a function in the stack; in case of 370*8e3e3a7aSWarner Losh ** errors, return an error code and an error message in the stack. 371*8e3e3a7aSWarner Losh */ 372*8e3e3a7aSWarner Losh static int lookforfunc (lua_State *L, const char *path, const char *sym) { 373*8e3e3a7aSWarner Losh void *reg = checkclib(L, path); /* check loaded C libraries */ 374*8e3e3a7aSWarner Losh if (reg == NULL) { /* must load library? */ 375*8e3e3a7aSWarner Losh reg = lsys_load(L, path, *sym == '*'); /* global symbols if 'sym'=='*' */ 376*8e3e3a7aSWarner Losh if (reg == NULL) return ERRLIB; /* unable to load library */ 377*8e3e3a7aSWarner Losh addtoclib(L, path, reg); 378*8e3e3a7aSWarner Losh } 379*8e3e3a7aSWarner Losh if (*sym == '*') { /* loading only library (no function)? */ 380*8e3e3a7aSWarner Losh lua_pushboolean(L, 1); /* return 'true' */ 381*8e3e3a7aSWarner Losh return 0; /* no errors */ 382*8e3e3a7aSWarner Losh } 383*8e3e3a7aSWarner Losh else { 384*8e3e3a7aSWarner Losh lua_CFunction f = lsys_sym(L, reg, sym); 385*8e3e3a7aSWarner Losh if (f == NULL) 386*8e3e3a7aSWarner Losh return ERRFUNC; /* unable to find function */ 387*8e3e3a7aSWarner Losh lua_pushcfunction(L, f); /* else create new function */ 388*8e3e3a7aSWarner Losh return 0; /* no errors */ 389*8e3e3a7aSWarner Losh } 390*8e3e3a7aSWarner Losh } 391*8e3e3a7aSWarner Losh 392*8e3e3a7aSWarner Losh 393*8e3e3a7aSWarner Losh static int ll_loadlib (lua_State *L) { 394*8e3e3a7aSWarner Losh const char *path = luaL_checkstring(L, 1); 395*8e3e3a7aSWarner Losh const char *init = luaL_checkstring(L, 2); 396*8e3e3a7aSWarner Losh int stat = lookforfunc(L, path, init); 397*8e3e3a7aSWarner Losh if (stat == 0) /* no errors? */ 398*8e3e3a7aSWarner Losh return 1; /* return the loaded function */ 399*8e3e3a7aSWarner Losh else { /* error; error message is on stack top */ 400*8e3e3a7aSWarner Losh lua_pushnil(L); 401*8e3e3a7aSWarner Losh lua_insert(L, -2); 402*8e3e3a7aSWarner Losh lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); 403*8e3e3a7aSWarner Losh return 3; /* return nil, error message, and where */ 404*8e3e3a7aSWarner Losh } 405*8e3e3a7aSWarner Losh } 406*8e3e3a7aSWarner Losh 407*8e3e3a7aSWarner Losh 408*8e3e3a7aSWarner Losh 409*8e3e3a7aSWarner Losh /* 410*8e3e3a7aSWarner Losh ** {====================================================== 411*8e3e3a7aSWarner Losh ** 'require' function 412*8e3e3a7aSWarner Losh ** ======================================================= 413*8e3e3a7aSWarner Losh */ 414*8e3e3a7aSWarner Losh 415*8e3e3a7aSWarner Losh 416*8e3e3a7aSWarner Losh static int readable (const char *filename) { 417*8e3e3a7aSWarner Losh FILE *f = fopen(filename, "r"); /* try to open file */ 418*8e3e3a7aSWarner Losh if (f == NULL) return 0; /* open failed */ 419*8e3e3a7aSWarner Losh fclose(f); 420*8e3e3a7aSWarner Losh return 1; 421*8e3e3a7aSWarner Losh } 422*8e3e3a7aSWarner Losh 423*8e3e3a7aSWarner Losh 424*8e3e3a7aSWarner Losh static const char *pushnexttemplate (lua_State *L, const char *path) { 425*8e3e3a7aSWarner Losh const char *l; 426*8e3e3a7aSWarner Losh while (*path == *LUA_PATH_SEP) path++; /* skip separators */ 427*8e3e3a7aSWarner Losh if (*path == '\0') return NULL; /* no more templates */ 428*8e3e3a7aSWarner Losh l = strchr(path, *LUA_PATH_SEP); /* find next separator */ 429*8e3e3a7aSWarner Losh if (l == NULL) l = path + strlen(path); 430*8e3e3a7aSWarner Losh lua_pushlstring(L, path, l - path); /* template */ 431*8e3e3a7aSWarner Losh return l; 432*8e3e3a7aSWarner Losh } 433*8e3e3a7aSWarner Losh 434*8e3e3a7aSWarner Losh 435*8e3e3a7aSWarner Losh static const char *searchpath (lua_State *L, const char *name, 436*8e3e3a7aSWarner Losh const char *path, 437*8e3e3a7aSWarner Losh const char *sep, 438*8e3e3a7aSWarner Losh const char *dirsep) { 439*8e3e3a7aSWarner Losh luaL_Buffer msg; /* to build error message */ 440*8e3e3a7aSWarner Losh luaL_buffinit(L, &msg); 441*8e3e3a7aSWarner Losh if (*sep != '\0') /* non-empty separator? */ 442*8e3e3a7aSWarner Losh name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ 443*8e3e3a7aSWarner Losh while ((path = pushnexttemplate(L, path)) != NULL) { 444*8e3e3a7aSWarner Losh const char *filename = luaL_gsub(L, lua_tostring(L, -1), 445*8e3e3a7aSWarner Losh LUA_PATH_MARK, name); 446*8e3e3a7aSWarner Losh lua_remove(L, -2); /* remove path template */ 447*8e3e3a7aSWarner Losh if (readable(filename)) /* does file exist and is readable? */ 448*8e3e3a7aSWarner Losh return filename; /* return that file name */ 449*8e3e3a7aSWarner Losh lua_pushfstring(L, "\n\tno file '%s'", filename); 450*8e3e3a7aSWarner Losh lua_remove(L, -2); /* remove file name */ 451*8e3e3a7aSWarner Losh luaL_addvalue(&msg); /* concatenate error msg. entry */ 452*8e3e3a7aSWarner Losh } 453*8e3e3a7aSWarner Losh luaL_pushresult(&msg); /* create error message */ 454*8e3e3a7aSWarner Losh return NULL; /* not found */ 455*8e3e3a7aSWarner Losh } 456*8e3e3a7aSWarner Losh 457*8e3e3a7aSWarner Losh 458*8e3e3a7aSWarner Losh static int ll_searchpath (lua_State *L) { 459*8e3e3a7aSWarner Losh const char *f = searchpath(L, luaL_checkstring(L, 1), 460*8e3e3a7aSWarner Losh luaL_checkstring(L, 2), 461*8e3e3a7aSWarner Losh luaL_optstring(L, 3, "."), 462*8e3e3a7aSWarner Losh luaL_optstring(L, 4, LUA_DIRSEP)); 463*8e3e3a7aSWarner Losh if (f != NULL) return 1; 464*8e3e3a7aSWarner Losh else { /* error message is on top of the stack */ 465*8e3e3a7aSWarner Losh lua_pushnil(L); 466*8e3e3a7aSWarner Losh lua_insert(L, -2); 467*8e3e3a7aSWarner Losh return 2; /* return nil + error message */ 468*8e3e3a7aSWarner Losh } 469*8e3e3a7aSWarner Losh } 470*8e3e3a7aSWarner Losh 471*8e3e3a7aSWarner Losh 472*8e3e3a7aSWarner Losh static const char *findfile (lua_State *L, const char *name, 473*8e3e3a7aSWarner Losh const char *pname, 474*8e3e3a7aSWarner Losh const char *dirsep) { 475*8e3e3a7aSWarner Losh const char *path; 476*8e3e3a7aSWarner Losh lua_getfield(L, lua_upvalueindex(1), pname); 477*8e3e3a7aSWarner Losh path = lua_tostring(L, -1); 478*8e3e3a7aSWarner Losh if (path == NULL) 479*8e3e3a7aSWarner Losh luaL_error(L, "'package.%s' must be a string", pname); 480*8e3e3a7aSWarner Losh return searchpath(L, name, path, ".", dirsep); 481*8e3e3a7aSWarner Losh } 482*8e3e3a7aSWarner Losh 483*8e3e3a7aSWarner Losh 484*8e3e3a7aSWarner Losh static int checkload (lua_State *L, int stat, const char *filename) { 485*8e3e3a7aSWarner Losh if (stat) { /* module loaded successfully? */ 486*8e3e3a7aSWarner Losh lua_pushstring(L, filename); /* will be 2nd argument to module */ 487*8e3e3a7aSWarner Losh return 2; /* return open function and file name */ 488*8e3e3a7aSWarner Losh } 489*8e3e3a7aSWarner Losh else 490*8e3e3a7aSWarner Losh return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s", 491*8e3e3a7aSWarner Losh lua_tostring(L, 1), filename, lua_tostring(L, -1)); 492*8e3e3a7aSWarner Losh } 493*8e3e3a7aSWarner Losh 494*8e3e3a7aSWarner Losh 495*8e3e3a7aSWarner Losh static int searcher_Lua (lua_State *L) { 496*8e3e3a7aSWarner Losh const char *filename; 497*8e3e3a7aSWarner Losh const char *name = luaL_checkstring(L, 1); 498*8e3e3a7aSWarner Losh filename = findfile(L, name, "path", LUA_LSUBSEP); 499*8e3e3a7aSWarner Losh if (filename == NULL) return 1; /* module not found in this path */ 500*8e3e3a7aSWarner Losh return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename); 501*8e3e3a7aSWarner Losh } 502*8e3e3a7aSWarner Losh 503*8e3e3a7aSWarner Losh 504*8e3e3a7aSWarner Losh /* 505*8e3e3a7aSWarner Losh ** Try to find a load function for module 'modname' at file 'filename'. 506*8e3e3a7aSWarner Losh ** First, change '.' to '_' in 'modname'; then, if 'modname' has 507*8e3e3a7aSWarner Losh ** the form X-Y (that is, it has an "ignore mark"), build a function 508*8e3e3a7aSWarner Losh ** name "luaopen_X" and look for it. (For compatibility, if that 509*8e3e3a7aSWarner Losh ** fails, it also tries "luaopen_Y".) If there is no ignore mark, 510*8e3e3a7aSWarner Losh ** look for a function named "luaopen_modname". 511*8e3e3a7aSWarner Losh */ 512*8e3e3a7aSWarner Losh static int loadfunc (lua_State *L, const char *filename, const char *modname) { 513*8e3e3a7aSWarner Losh const char *openfunc; 514*8e3e3a7aSWarner Losh const char *mark; 515*8e3e3a7aSWarner Losh modname = luaL_gsub(L, modname, ".", LUA_OFSEP); 516*8e3e3a7aSWarner Losh mark = strchr(modname, *LUA_IGMARK); 517*8e3e3a7aSWarner Losh if (mark) { 518*8e3e3a7aSWarner Losh int stat; 519*8e3e3a7aSWarner Losh openfunc = lua_pushlstring(L, modname, mark - modname); 520*8e3e3a7aSWarner Losh openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc); 521*8e3e3a7aSWarner Losh stat = lookforfunc(L, filename, openfunc); 522*8e3e3a7aSWarner Losh if (stat != ERRFUNC) return stat; 523*8e3e3a7aSWarner Losh modname = mark + 1; /* else go ahead and try old-style name */ 524*8e3e3a7aSWarner Losh } 525*8e3e3a7aSWarner Losh openfunc = lua_pushfstring(L, LUA_POF"%s", modname); 526*8e3e3a7aSWarner Losh return lookforfunc(L, filename, openfunc); 527*8e3e3a7aSWarner Losh } 528*8e3e3a7aSWarner Losh 529*8e3e3a7aSWarner Losh 530*8e3e3a7aSWarner Losh static int searcher_C (lua_State *L) { 531*8e3e3a7aSWarner Losh const char *name = luaL_checkstring(L, 1); 532*8e3e3a7aSWarner Losh const char *filename = findfile(L, name, "cpath", LUA_CSUBSEP); 533*8e3e3a7aSWarner Losh if (filename == NULL) return 1; /* module not found in this path */ 534*8e3e3a7aSWarner Losh return checkload(L, (loadfunc(L, filename, name) == 0), filename); 535*8e3e3a7aSWarner Losh } 536*8e3e3a7aSWarner Losh 537*8e3e3a7aSWarner Losh 538*8e3e3a7aSWarner Losh static int searcher_Croot (lua_State *L) { 539*8e3e3a7aSWarner Losh const char *filename; 540*8e3e3a7aSWarner Losh const char *name = luaL_checkstring(L, 1); 541*8e3e3a7aSWarner Losh const char *p = strchr(name, '.'); 542*8e3e3a7aSWarner Losh int stat; 543*8e3e3a7aSWarner Losh if (p == NULL) return 0; /* is root */ 544*8e3e3a7aSWarner Losh lua_pushlstring(L, name, p - name); 545*8e3e3a7aSWarner Losh filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP); 546*8e3e3a7aSWarner Losh if (filename == NULL) return 1; /* root not found */ 547*8e3e3a7aSWarner Losh if ((stat = loadfunc(L, filename, name)) != 0) { 548*8e3e3a7aSWarner Losh if (stat != ERRFUNC) 549*8e3e3a7aSWarner Losh return checkload(L, 0, filename); /* real error */ 550*8e3e3a7aSWarner Losh else { /* open function not found */ 551*8e3e3a7aSWarner Losh lua_pushfstring(L, "\n\tno module '%s' in file '%s'", name, filename); 552*8e3e3a7aSWarner Losh return 1; 553*8e3e3a7aSWarner Losh } 554*8e3e3a7aSWarner Losh } 555*8e3e3a7aSWarner Losh lua_pushstring(L, filename); /* will be 2nd argument to module */ 556*8e3e3a7aSWarner Losh return 2; 557*8e3e3a7aSWarner Losh } 558*8e3e3a7aSWarner Losh 559*8e3e3a7aSWarner Losh 560*8e3e3a7aSWarner Losh static int searcher_preload (lua_State *L) { 561*8e3e3a7aSWarner Losh const char *name = luaL_checkstring(L, 1); 562*8e3e3a7aSWarner Losh lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); 563*8e3e3a7aSWarner Losh if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */ 564*8e3e3a7aSWarner Losh lua_pushfstring(L, "\n\tno field package.preload['%s']", name); 565*8e3e3a7aSWarner Losh return 1; 566*8e3e3a7aSWarner Losh } 567*8e3e3a7aSWarner Losh 568*8e3e3a7aSWarner Losh 569*8e3e3a7aSWarner Losh static void findloader (lua_State *L, const char *name) { 570*8e3e3a7aSWarner Losh int i; 571*8e3e3a7aSWarner Losh luaL_Buffer msg; /* to build error message */ 572*8e3e3a7aSWarner Losh luaL_buffinit(L, &msg); 573*8e3e3a7aSWarner Losh /* push 'package.searchers' to index 3 in the stack */ 574*8e3e3a7aSWarner Losh if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE) 575*8e3e3a7aSWarner Losh luaL_error(L, "'package.searchers' must be a table"); 576*8e3e3a7aSWarner Losh /* iterate over available searchers to find a loader */ 577*8e3e3a7aSWarner Losh for (i = 1; ; i++) { 578*8e3e3a7aSWarner Losh if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */ 579*8e3e3a7aSWarner Losh lua_pop(L, 1); /* remove nil */ 580*8e3e3a7aSWarner Losh luaL_pushresult(&msg); /* create error message */ 581*8e3e3a7aSWarner Losh luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1)); 582*8e3e3a7aSWarner Losh } 583*8e3e3a7aSWarner Losh lua_pushstring(L, name); 584*8e3e3a7aSWarner Losh lua_call(L, 1, 2); /* call it */ 585*8e3e3a7aSWarner Losh if (lua_isfunction(L, -2)) /* did it find a loader? */ 586*8e3e3a7aSWarner Losh return; /* module loader found */ 587*8e3e3a7aSWarner Losh else if (lua_isstring(L, -2)) { /* searcher returned error message? */ 588*8e3e3a7aSWarner Losh lua_pop(L, 1); /* remove extra return */ 589*8e3e3a7aSWarner Losh luaL_addvalue(&msg); /* concatenate error message */ 590*8e3e3a7aSWarner Losh } 591*8e3e3a7aSWarner Losh else 592*8e3e3a7aSWarner Losh lua_pop(L, 2); /* remove both returns */ 593*8e3e3a7aSWarner Losh } 594*8e3e3a7aSWarner Losh } 595*8e3e3a7aSWarner Losh 596*8e3e3a7aSWarner Losh 597*8e3e3a7aSWarner Losh static int ll_require (lua_State *L) { 598*8e3e3a7aSWarner Losh const char *name = luaL_checkstring(L, 1); 599*8e3e3a7aSWarner Losh lua_settop(L, 1); /* LOADED table will be at index 2 */ 600*8e3e3a7aSWarner Losh lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); 601*8e3e3a7aSWarner Losh lua_getfield(L, 2, name); /* LOADED[name] */ 602*8e3e3a7aSWarner Losh if (lua_toboolean(L, -1)) /* is it there? */ 603*8e3e3a7aSWarner Losh return 1; /* package is already loaded */ 604*8e3e3a7aSWarner Losh /* else must load package */ 605*8e3e3a7aSWarner Losh lua_pop(L, 1); /* remove 'getfield' result */ 606*8e3e3a7aSWarner Losh findloader(L, name); 607*8e3e3a7aSWarner Losh lua_pushstring(L, name); /* pass name as argument to module loader */ 608*8e3e3a7aSWarner Losh lua_insert(L, -2); /* name is 1st argument (before search data) */ 609*8e3e3a7aSWarner Losh lua_call(L, 2, 1); /* run loader to load module */ 610*8e3e3a7aSWarner Losh if (!lua_isnil(L, -1)) /* non-nil return? */ 611*8e3e3a7aSWarner Losh lua_setfield(L, 2, name); /* LOADED[name] = returned value */ 612*8e3e3a7aSWarner Losh if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */ 613*8e3e3a7aSWarner Losh lua_pushboolean(L, 1); /* use true as result */ 614*8e3e3a7aSWarner Losh lua_pushvalue(L, -1); /* extra copy to be returned */ 615*8e3e3a7aSWarner Losh lua_setfield(L, 2, name); /* LOADED[name] = true */ 616*8e3e3a7aSWarner Losh } 617*8e3e3a7aSWarner Losh return 1; 618*8e3e3a7aSWarner Losh } 619*8e3e3a7aSWarner Losh 620*8e3e3a7aSWarner Losh /* }====================================================== */ 621*8e3e3a7aSWarner Losh 622*8e3e3a7aSWarner Losh 623*8e3e3a7aSWarner Losh 624*8e3e3a7aSWarner Losh /* 625*8e3e3a7aSWarner Losh ** {====================================================== 626*8e3e3a7aSWarner Losh ** 'module' function 627*8e3e3a7aSWarner Losh ** ======================================================= 628*8e3e3a7aSWarner Losh */ 629*8e3e3a7aSWarner Losh #if defined(LUA_COMPAT_MODULE) 630*8e3e3a7aSWarner Losh 631*8e3e3a7aSWarner Losh /* 632*8e3e3a7aSWarner Losh ** changes the environment variable of calling function 633*8e3e3a7aSWarner Losh */ 634*8e3e3a7aSWarner Losh static void set_env (lua_State *L) { 635*8e3e3a7aSWarner Losh lua_Debug ar; 636*8e3e3a7aSWarner Losh if (lua_getstack(L, 1, &ar) == 0 || 637*8e3e3a7aSWarner Losh lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ 638*8e3e3a7aSWarner Losh lua_iscfunction(L, -1)) 639*8e3e3a7aSWarner Losh luaL_error(L, "'module' not called from a Lua function"); 640*8e3e3a7aSWarner Losh lua_pushvalue(L, -2); /* copy new environment table to top */ 641*8e3e3a7aSWarner Losh lua_setupvalue(L, -2, 1); 642*8e3e3a7aSWarner Losh lua_pop(L, 1); /* remove function */ 643*8e3e3a7aSWarner Losh } 644*8e3e3a7aSWarner Losh 645*8e3e3a7aSWarner Losh 646*8e3e3a7aSWarner Losh static void dooptions (lua_State *L, int n) { 647*8e3e3a7aSWarner Losh int i; 648*8e3e3a7aSWarner Losh for (i = 2; i <= n; i++) { 649*8e3e3a7aSWarner Losh if (lua_isfunction(L, i)) { /* avoid 'calling' extra info. */ 650*8e3e3a7aSWarner Losh lua_pushvalue(L, i); /* get option (a function) */ 651*8e3e3a7aSWarner Losh lua_pushvalue(L, -2); /* module */ 652*8e3e3a7aSWarner Losh lua_call(L, 1, 0); 653*8e3e3a7aSWarner Losh } 654*8e3e3a7aSWarner Losh } 655*8e3e3a7aSWarner Losh } 656*8e3e3a7aSWarner Losh 657*8e3e3a7aSWarner Losh 658*8e3e3a7aSWarner Losh static void modinit (lua_State *L, const char *modname) { 659*8e3e3a7aSWarner Losh const char *dot; 660*8e3e3a7aSWarner Losh lua_pushvalue(L, -1); 661*8e3e3a7aSWarner Losh lua_setfield(L, -2, "_M"); /* module._M = module */ 662*8e3e3a7aSWarner Losh lua_pushstring(L, modname); 663*8e3e3a7aSWarner Losh lua_setfield(L, -2, "_NAME"); 664*8e3e3a7aSWarner Losh dot = strrchr(modname, '.'); /* look for last dot in module name */ 665*8e3e3a7aSWarner Losh if (dot == NULL) dot = modname; 666*8e3e3a7aSWarner Losh else dot++; 667*8e3e3a7aSWarner Losh /* set _PACKAGE as package name (full module name minus last part) */ 668*8e3e3a7aSWarner Losh lua_pushlstring(L, modname, dot - modname); 669*8e3e3a7aSWarner Losh lua_setfield(L, -2, "_PACKAGE"); 670*8e3e3a7aSWarner Losh } 671*8e3e3a7aSWarner Losh 672*8e3e3a7aSWarner Losh 673*8e3e3a7aSWarner Losh static int ll_module (lua_State *L) { 674*8e3e3a7aSWarner Losh const char *modname = luaL_checkstring(L, 1); 675*8e3e3a7aSWarner Losh int lastarg = lua_gettop(L); /* last parameter */ 676*8e3e3a7aSWarner Losh luaL_pushmodule(L, modname, 1); /* get/create module table */ 677*8e3e3a7aSWarner Losh /* check whether table already has a _NAME field */ 678*8e3e3a7aSWarner Losh if (lua_getfield(L, -1, "_NAME") != LUA_TNIL) 679*8e3e3a7aSWarner Losh lua_pop(L, 1); /* table is an initialized module */ 680*8e3e3a7aSWarner Losh else { /* no; initialize it */ 681*8e3e3a7aSWarner Losh lua_pop(L, 1); 682*8e3e3a7aSWarner Losh modinit(L, modname); 683*8e3e3a7aSWarner Losh } 684*8e3e3a7aSWarner Losh lua_pushvalue(L, -1); 685*8e3e3a7aSWarner Losh set_env(L); 686*8e3e3a7aSWarner Losh dooptions(L, lastarg); 687*8e3e3a7aSWarner Losh return 1; 688*8e3e3a7aSWarner Losh } 689*8e3e3a7aSWarner Losh 690*8e3e3a7aSWarner Losh 691*8e3e3a7aSWarner Losh static int ll_seeall (lua_State *L) { 692*8e3e3a7aSWarner Losh luaL_checktype(L, 1, LUA_TTABLE); 693*8e3e3a7aSWarner Losh if (!lua_getmetatable(L, 1)) { 694*8e3e3a7aSWarner Losh lua_createtable(L, 0, 1); /* create new metatable */ 695*8e3e3a7aSWarner Losh lua_pushvalue(L, -1); 696*8e3e3a7aSWarner Losh lua_setmetatable(L, 1); 697*8e3e3a7aSWarner Losh } 698*8e3e3a7aSWarner Losh lua_pushglobaltable(L); 699*8e3e3a7aSWarner Losh lua_setfield(L, -2, "__index"); /* mt.__index = _G */ 700*8e3e3a7aSWarner Losh return 0; 701*8e3e3a7aSWarner Losh } 702*8e3e3a7aSWarner Losh 703*8e3e3a7aSWarner Losh #endif 704*8e3e3a7aSWarner Losh /* }====================================================== */ 705*8e3e3a7aSWarner Losh 706*8e3e3a7aSWarner Losh 707*8e3e3a7aSWarner Losh 708*8e3e3a7aSWarner Losh static const luaL_Reg pk_funcs[] = { 709*8e3e3a7aSWarner Losh {"loadlib", ll_loadlib}, 710*8e3e3a7aSWarner Losh {"searchpath", ll_searchpath}, 711*8e3e3a7aSWarner Losh #if defined(LUA_COMPAT_MODULE) 712*8e3e3a7aSWarner Losh {"seeall", ll_seeall}, 713*8e3e3a7aSWarner Losh #endif 714*8e3e3a7aSWarner Losh /* placeholders */ 715*8e3e3a7aSWarner Losh {"preload", NULL}, 716*8e3e3a7aSWarner Losh {"cpath", NULL}, 717*8e3e3a7aSWarner Losh {"path", NULL}, 718*8e3e3a7aSWarner Losh {"searchers", NULL}, 719*8e3e3a7aSWarner Losh {"loaded", NULL}, 720*8e3e3a7aSWarner Losh {NULL, NULL} 721*8e3e3a7aSWarner Losh }; 722*8e3e3a7aSWarner Losh 723*8e3e3a7aSWarner Losh 724*8e3e3a7aSWarner Losh static const luaL_Reg ll_funcs[] = { 725*8e3e3a7aSWarner Losh #if defined(LUA_COMPAT_MODULE) 726*8e3e3a7aSWarner Losh {"module", ll_module}, 727*8e3e3a7aSWarner Losh #endif 728*8e3e3a7aSWarner Losh {"require", ll_require}, 729*8e3e3a7aSWarner Losh {NULL, NULL} 730*8e3e3a7aSWarner Losh }; 731*8e3e3a7aSWarner Losh 732*8e3e3a7aSWarner Losh 733*8e3e3a7aSWarner Losh static void createsearcherstable (lua_State *L) { 734*8e3e3a7aSWarner Losh static const lua_CFunction searchers[] = 735*8e3e3a7aSWarner Losh {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; 736*8e3e3a7aSWarner Losh int i; 737*8e3e3a7aSWarner Losh /* create 'searchers' table */ 738*8e3e3a7aSWarner Losh lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); 739*8e3e3a7aSWarner Losh /* fill it with predefined searchers */ 740*8e3e3a7aSWarner Losh for (i=0; searchers[i] != NULL; i++) { 741*8e3e3a7aSWarner Losh lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ 742*8e3e3a7aSWarner Losh lua_pushcclosure(L, searchers[i], 1); 743*8e3e3a7aSWarner Losh lua_rawseti(L, -2, i+1); 744*8e3e3a7aSWarner Losh } 745*8e3e3a7aSWarner Losh #if defined(LUA_COMPAT_LOADERS) 746*8e3e3a7aSWarner Losh lua_pushvalue(L, -1); /* make a copy of 'searchers' table */ 747*8e3e3a7aSWarner Losh lua_setfield(L, -3, "loaders"); /* put it in field 'loaders' */ 748*8e3e3a7aSWarner Losh #endif 749*8e3e3a7aSWarner Losh lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ 750*8e3e3a7aSWarner Losh } 751*8e3e3a7aSWarner Losh 752*8e3e3a7aSWarner Losh 753*8e3e3a7aSWarner Losh /* 754*8e3e3a7aSWarner Losh ** create table CLIBS to keep track of loaded C libraries, 755*8e3e3a7aSWarner Losh ** setting a finalizer to close all libraries when closing state. 756*8e3e3a7aSWarner Losh */ 757*8e3e3a7aSWarner Losh static void createclibstable (lua_State *L) { 758*8e3e3a7aSWarner Losh lua_newtable(L); /* create CLIBS table */ 759*8e3e3a7aSWarner Losh lua_createtable(L, 0, 1); /* create metatable for CLIBS */ 760*8e3e3a7aSWarner Losh lua_pushcfunction(L, gctm); 761*8e3e3a7aSWarner Losh lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ 762*8e3e3a7aSWarner Losh lua_setmetatable(L, -2); 763*8e3e3a7aSWarner Losh lua_rawsetp(L, LUA_REGISTRYINDEX, &CLIBS); /* set CLIBS table in registry */ 764*8e3e3a7aSWarner Losh } 765*8e3e3a7aSWarner Losh 766*8e3e3a7aSWarner Losh 767*8e3e3a7aSWarner Losh LUAMOD_API int luaopen_package (lua_State *L) { 768*8e3e3a7aSWarner Losh createclibstable(L); 769*8e3e3a7aSWarner Losh luaL_newlib(L, pk_funcs); /* create 'package' table */ 770*8e3e3a7aSWarner Losh createsearcherstable(L); 771*8e3e3a7aSWarner Losh /* set paths */ 772*8e3e3a7aSWarner Losh setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT); 773*8e3e3a7aSWarner Losh setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT); 774*8e3e3a7aSWarner Losh /* store config information */ 775*8e3e3a7aSWarner Losh lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" 776*8e3e3a7aSWarner Losh LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); 777*8e3e3a7aSWarner Losh lua_setfield(L, -2, "config"); 778*8e3e3a7aSWarner Losh /* set field 'loaded' */ 779*8e3e3a7aSWarner Losh luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); 780*8e3e3a7aSWarner Losh lua_setfield(L, -2, "loaded"); 781*8e3e3a7aSWarner Losh /* set field 'preload' */ 782*8e3e3a7aSWarner Losh luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); 783*8e3e3a7aSWarner Losh lua_setfield(L, -2, "preload"); 784*8e3e3a7aSWarner Losh lua_pushglobaltable(L); 785*8e3e3a7aSWarner Losh lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ 786*8e3e3a7aSWarner Losh luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */ 787*8e3e3a7aSWarner Losh lua_pop(L, 1); /* pop global table */ 788*8e3e3a7aSWarner Losh return 1; /* return 'package' table */ 789*8e3e3a7aSWarner Losh } 790*8e3e3a7aSWarner Losh 791