Lua TeamLua 5.3.0dcf748911 years agoHistory
786 lines · 23.0 KB · C
RawDownload
/*** $Id: loadlib.c,v 1.124 2015/01/05 13:51:39 roberto Exp $** Dynamic library loader for Lua** See Copyright Notice in lua.h**** This module contains an implementation of loadlib for Unix systems** that have dlfcn, an implementation for Windows, and a stub for other** systems.*/ #define loadlib_c#define LUA_LIB #include "lprefix.h"  #include <stdlib.h>#include <string.h> #include "lua.h" #include "lauxlib.h"#include "lualib.h"  /*** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment** variables that Lua check to set its paths.*/#if !defined(LUA_PATH_VAR)#define LUA_PATH_VAR	"LUA_PATH"#endif #if !defined(LUA_CPATH_VAR)#define LUA_CPATH_VAR	"LUA_CPATH"#endif #define LUA_PATHSUFFIX		"_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR #define LUA_PATHVARVERSION		LUA_PATH_VAR LUA_PATHSUFFIX#define LUA_CPATHVARVERSION		LUA_CPATH_VAR LUA_PATHSUFFIX /*** LUA_PATH_SEP is the character that separates templates in a path.** LUA_PATH_MARK is the string that marks the substitution points in a** template.** LUA_EXEC_DIR in a Windows path is replaced by the executable's** directory.** LUA_IGMARK is a mark to ignore all before it when building the** luaopen_ function name.*/#if !defined (LUA_PATH_SEP)#define LUA_PATH_SEP		";"#endif#if !defined (LUA_PATH_MARK)#define LUA_PATH_MARK		"?"#endif#if !defined (LUA_EXEC_DIR)#define LUA_EXEC_DIR		"!"#endif#if !defined (LUA_IGMARK)#define LUA_IGMARK		"-"#endif  /*** LUA_CSUBSEP is the character that replaces dots in submodule names** when searching for a C loader.** LUA_LSUBSEP is the character that replaces dots in submodule names** when searching for a Lua loader.*/#if !defined(LUA_CSUBSEP)#define LUA_CSUBSEP		LUA_DIRSEP#endif #if !defined(LUA_LSUBSEP)#define LUA_LSUBSEP		LUA_DIRSEP#endif  /* prefix for open functions in C libraries */#define LUA_POF		"luaopen_" /* separator for open functions in C libraries */#define LUA_OFSEP	"_"  /*** unique key for table in the registry that keeps handles** for all loaded C libraries*/static const int CLIBS = 0; #define LIB_FAIL	"open" #define setprogdir(L)		((void)0)  /*** system-dependent functions*/ /*** unload library 'lib'*/static void lsys_unloadlib (void *lib); /*** load C library in file 'path'. If 'seeglb', load with all names in** the library global.** Returns the library; in case of error, returns NULL plus an** error string in the stack.*/static void *lsys_load (lua_State *L, const char *path, int seeglb); /*** Try to find a function named 'sym' in library 'lib'.** Returns the function; in case of error, returns NULL plus an** error string in the stack.*/static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym);    #if defined(LUA_USE_DLOPEN)	/* { *//*** {========================================================================** This is an implementation of loadlib based on the dlfcn interface.** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,** NetBSD, AIX 4.2, HPUX 11, and  probably most other Unix flavors, at least** as an emulation layer on top of native functions.** =========================================================================*/ #include <dlfcn.h> /*** Macro to covert pointer to void* to pointer to function. This cast** is undefined according to ISO C, but POSIX assumes that it must work.** (The '__extension__' in gnu compilers is only to avoid warnings.)*/#if defined(__GNUC__)#define cast_func(p) (__extension__ (lua_CFunction)(p))#else#define cast_func(p) ((lua_CFunction)(p))#endif  static void lsys_unloadlib (void *lib) {  dlclose(lib);}  static void *lsys_load (lua_State *L, const char *path, int seeglb) {  void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL));  if (lib == NULL) lua_pushstring(L, dlerror());  return lib;}  static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {  lua_CFunction f = cast_func(dlsym(lib, sym));  if (f == NULL) lua_pushstring(L, dlerror());  return f;} /* }====================================================== */   #elif defined(LUA_DL_DLL)	/* }{ *//*** {======================================================================** This is an implementation of loadlib for Windows using native functions.** =======================================================================*/ #include <windows.h> #undef setprogdir /*** optional flags for LoadLibraryEx*/#if !defined(LUA_LLE_FLAGS)#define LUA_LLE_FLAGS	0#endif  static void setprogdir (lua_State *L) {  char buff[MAX_PATH + 1];  char *lb;  DWORD nsize = sizeof(buff)/sizeof(char);  DWORD n = GetModuleFileNameA(NULL, buff, nsize);  if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL)    luaL_error(L, "unable to get ModuleFileName");  else {    *lb = '\0';    luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff);    lua_remove(L, -2);  /* remove original string */  }}  static void pusherror (lua_State *L) {  int error = GetLastError();  char buffer[128];  if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,      NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL))    lua_pushstring(L, buffer);  else    lua_pushfstring(L, "system error %d\n", error);} static void lsys_unloadlib (void *lib) {  FreeLibrary((HMODULE)lib);}  static void *lsys_load (lua_State *L, const char *path, int seeglb) {  HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS);  (void)(seeglb);  /* not used: symbols are 'global' by default */  if (lib == NULL) pusherror(L);  return lib;}  static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {  lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym);  if (f == NULL) pusherror(L);  return f;} /* }====================================================== */  #else				/* }{ *//*** {======================================================** Fallback for other systems** =======================================================*/ #undef LIB_FAIL#define LIB_FAIL	"absent"  #define DLMSG	"dynamic libraries not enabled; check your Lua installation"  static void lsys_unloadlib (void *lib) {  (void)(lib);  /* not used */}  static void *lsys_load (lua_State *L, const char *path, int seeglb) {  (void)(path); (void)(seeglb);  /* not used */  lua_pushliteral(L, DLMSG);  return NULL;}  static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {  (void)(lib); (void)(sym);  /* not used */  lua_pushliteral(L, DLMSG);  return NULL;} /* }====================================================== */#endif				/* } */  /*** return registry.CLIBS[path]*/static void *checkclib (lua_State *L, const char *path) {  void *plib;  lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS);  lua_getfield(L, -1, path);  plib = lua_touserdata(L, -1);  /* plib = CLIBS[path] */  lua_pop(L, 2);  /* pop CLIBS table and 'plib' */  return plib;}  /*** registry.CLIBS[path] = plib        -- for queries** registry.CLIBS[#CLIBS + 1] = plib  -- also keep a list of all libraries*/static void addtoclib (lua_State *L, const char *path, void *plib) {  lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS);  lua_pushlightuserdata(L, plib);  lua_pushvalue(L, -1);  lua_setfield(L, -3, path);  /* CLIBS[path] = plib */  lua_rawseti(L, -2, luaL_len(L, -2) + 1);  /* CLIBS[#CLIBS + 1] = plib */  lua_pop(L, 1);  /* pop CLIBS table */}  /*** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib** handles in list CLIBS*/static int gctm (lua_State *L) {  lua_Integer n = luaL_len(L, 1);  for (; n >= 1; n--) {  /* for each handle, in reverse order */    lua_rawgeti(L, 1, n);  /* get handle CLIBS[n] */    lsys_unloadlib(lua_touserdata(L, -1));    lua_pop(L, 1);  /* pop handle */  }  return 0;}   /* error codes for 'lookforfunc' */#define ERRLIB		1#define ERRFUNC		2 /*** Look for a C function named 'sym' in a dynamically loaded library** 'path'.** First, check whether the library is already loaded; if not, try** to load it.** Then, if 'sym' is '*', return true (as library has been loaded).** Otherwise, look for symbol 'sym' in the library and push a** C function with that symbol.** Return 0 and 'true' or a function in the stack; in case of** errors, return an error code and an error message in the stack.*/static int lookforfunc (lua_State *L, const char *path, const char *sym) {  void *reg = checkclib(L, path);  /* check loaded C libraries */  if (reg == NULL) {  /* must load library? */    reg = lsys_load(L, path, *sym == '*');  /* global symbols if 'sym'=='*' */    if (reg == NULL) return ERRLIB;  /* unable to load library */    addtoclib(L, path, reg);  }  if (*sym == '*') {  /* loading only library (no function)? */    lua_pushboolean(L, 1);  /* return 'true' */    return 0;  /* no errors */  }  else {    lua_CFunction f = lsys_sym(L, reg, sym);    if (f == NULL)      return ERRFUNC;  /* unable to find function */    lua_pushcfunction(L, f);  /* else create new function */    return 0;  /* no errors */  }}  static int ll_loadlib (lua_State *L) {  const char *path = luaL_checkstring(L, 1);  const char *init = luaL_checkstring(L, 2);  int stat = lookforfunc(L, path, init);  if (stat == 0)  /* no errors? */    return 1;  /* return the loaded function */  else {  /* error; error message is on stack top */    lua_pushnil(L);    lua_insert(L, -2);    lua_pushstring(L, (stat == ERRLIB) ?  LIB_FAIL : "init");    return 3;  /* return nil, error message, and where */  }}   /*** {======================================================** 'require' function** =======================================================*/  static int readable (const char *filename) {  FILE *f = fopen(filename, "r");  /* try to open file */  if (f == NULL) return 0;  /* open failed */  fclose(f);  return 1;}  static const char *pushnexttemplate (lua_State *L, const char *path) {  const char *l;  while (*path == *LUA_PATH_SEP) path++;  /* skip separators */  if (*path == '\0') return NULL;  /* no more templates */  l = strchr(path, *LUA_PATH_SEP);  /* find next separator */  if (l == NULL) l = path + strlen(path);  lua_pushlstring(L, path, l - path);  /* template */  return l;}  static const char *searchpath (lua_State *L, const char *name,                                             const char *path,                                             const char *sep,                                             const char *dirsep) {  luaL_Buffer msg;  /* to build error message */  luaL_buffinit(L, &msg);  if (*sep != '\0')  /* non-empty separator? */    name = luaL_gsub(L, name, sep, dirsep);  /* replace it by 'dirsep' */  while ((path = pushnexttemplate(L, path)) != NULL) {    const char *filename = luaL_gsub(L, lua_tostring(L, -1),                                     LUA_PATH_MARK, name);    lua_remove(L, -2);  /* remove path template */    if (readable(filename))  /* does file exist and is readable? */      return filename;  /* return that file name */    lua_pushfstring(L, "\n\tno file '%s'", filename);    lua_remove(L, -2);  /* remove file name */    luaL_addvalue(&msg);  /* concatenate error msg. entry */  }  luaL_pushresult(&msg);  /* create error message */  return NULL;  /* not found */}  static int ll_searchpath (lua_State *L) {  const char *f = searchpath(L, luaL_checkstring(L, 1),                                luaL_checkstring(L, 2),                                luaL_optstring(L, 3, "."),                                luaL_optstring(L, 4, LUA_DIRSEP));  if (f != NULL) return 1;  else {  /* error message is on top of the stack */    lua_pushnil(L);    lua_insert(L, -2);    return 2;  /* return nil + error message */  }}  static const char *findfile (lua_State *L, const char *name,                                           const char *pname,                                           const char *dirsep) {  const char *path;  lua_getfield(L, lua_upvalueindex(1), pname);  path = lua_tostring(L, -1);  if (path == NULL)    luaL_error(L, "'package.%s' must be a string", pname);  return searchpath(L, name, path, ".", dirsep);}  static int checkload (lua_State *L, int stat, const char *filename) {  if (stat) {  /* module loaded successfully? */    lua_pushstring(L, filename);  /* will be 2nd argument to module */    return 2;  /* return open function and file name */  }  else    return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s",                          lua_tostring(L, 1), filename, lua_tostring(L, -1));}  static int searcher_Lua (lua_State *L) {  const char *filename;  const char *name = luaL_checkstring(L, 1);  filename = findfile(L, name, "path", LUA_LSUBSEP);  if (filename == NULL) return 1;  /* module not found in this path */  return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename);}  /*** Try to find a load function for module 'modname' at file 'filename'.** First, change '.' to '_' in 'modname'; then, if 'modname' has** the form X-Y (that is, it has an "ignore mark"), build a function** name "luaopen_X" and look for it. (For compatibility, if that** fails, it also tries "luaopen_Y".) If there is no ignore mark,** look for a function named "luaopen_modname".*/static int loadfunc (lua_State *L, const char *filename, const char *modname) {  const char *openfunc;  const char *mark;  modname = luaL_gsub(L, modname, ".", LUA_OFSEP);  mark = strchr(modname, *LUA_IGMARK);  if (mark) {    int stat;    openfunc = lua_pushlstring(L, modname, mark - modname);    openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc);    stat = lookforfunc(L, filename, openfunc);    if (stat != ERRFUNC) return stat;    modname = mark + 1;  /* else go ahead and try old-style name */  }  openfunc = lua_pushfstring(L, LUA_POF"%s", modname);  return lookforfunc(L, filename, openfunc);}  static int searcher_C (lua_State *L) {  const char *name = luaL_checkstring(L, 1);  const char *filename = findfile(L, name, "cpath", LUA_CSUBSEP);  if (filename == NULL) return 1;  /* module not found in this path */  return checkload(L, (loadfunc(L, filename, name) == 0), filename);}  static int searcher_Croot (lua_State *L) {  const char *filename;  const char *name = luaL_checkstring(L, 1);

Lines 1–500 of 786.