diff options
Diffstat (limited to 'loadlib.c')
-rw-r--r-- | loadlib.c | 324 |
1 files changed, 182 insertions, 142 deletions
@@ -1,28 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: loadlib.c,v 1.12 2004/12/13 12:14:21 roberto Exp roberto $ | 2 | ** $Id: loadlib.c,v 1.13 2004/12/22 17:43:27 roberto Exp roberto $ |
3 | ** Dynamic library loader for Lua | 3 | ** Dynamic library loader for Lua |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | * | 5 | * |
6 | * This Lua library exports a single function, called loadlib, which | ||
7 | * is called from Lua as loadlib(lib,init), where lib is the full | ||
8 | * name of the library to be loaded (including the complete path) and | ||
9 | * init is the name of a function to be called after the library is | ||
10 | * loaded. Typically, this function will register other functions, thus | ||
11 | * making the complete library available to Lua. The init function is | ||
12 | * *not* automatically called by loadlib. Instead, loadlib returns the | ||
13 | * init function as a Lua function that the client can call when it | ||
14 | * thinks is appropriate. In the case of errors, loadlib returns nil and | ||
15 | * two strings describing the error. The first string is supplied by | ||
16 | * the operating system; it should be informative and useful for error | ||
17 | * messages. The second string is "open", "init", or "absent" to identify | ||
18 | * the error and is meant to be used for making decisions without having | ||
19 | * to look into the first string (whose format is system-dependent). | ||
20 | * This module contains an implementation of loadlib for Unix systems | 6 | * This module contains an implementation of loadlib for Unix systems |
21 | * that have dlfcn, an implementation for Darwin (Mac OS X), an | 7 | * that have dlfcn, an implementation for Darwin (Mac OS X), an |
22 | * implementation for Windows, and a stub for other systems. See | 8 | * implementation for Windows, and a stub for other systems. |
23 | * the list at the end of this file for some links to available | ||
24 | * implementations of dlfcn and interfaces to other native dynamic | ||
25 | * loaders on top of which loadlib could be implemented. | ||
26 | */ | 9 | */ |
27 | 10 | ||
28 | 11 | ||
@@ -38,96 +21,106 @@ | |||
38 | #include "lualib.h" | 21 | #include "lualib.h" |
39 | 22 | ||
40 | 23 | ||
41 | #define ERR_OPEN 1 | 24 | #define LIBPREFIX "LOADLIB: " |
42 | #define ERR_FUNCTION 2 | ||
43 | #define ERR_ABSENT 3 | ||
44 | 25 | ||
26 | #define POF LUA_POF | ||
27 | #define LIB_FAIL "open" | ||
28 | |||
29 | |||
30 | static void ll_unloadlib (void *lib); | ||
31 | static void *ll_load (lua_State *L, const char *path); | ||
32 | static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); | ||
45 | 33 | ||
46 | static void registerlib (lua_State *L, const void *lib); | ||
47 | 34 | ||
48 | 35 | ||
49 | #if defined(USE_DLOPEN) | 36 | #if defined(USE_DLOPEN) |
50 | /* | 37 | /* |
51 | * This is an implementation of loadlib based on the dlfcn interface. | 38 | ** {======================================================================== |
52 | * The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, | 39 | ** This is an implementation of loadlib based on the dlfcn interface. |
53 | * NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least | 40 | ** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, |
54 | * as an emulation layer on top of native functions. | 41 | ** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least |
42 | ** as an emulation layer on top of native functions. | ||
43 | ** ========================================================================= | ||
55 | */ | 44 | */ |
56 | 45 | ||
57 | #include <dlfcn.h> | 46 | #include <dlfcn.h> |
58 | 47 | ||
59 | #define freelib dlclose | 48 | static void ll_unloadlib (void *lib) { |
60 | 49 | dlclose(lib); | |
61 | static int loadlib(lua_State *L, const char *path, const char *init) { | 50 | } |
62 | void *lib=dlopen(path,RTLD_NOW); | 51 | |
63 | if (lib != NULL) { | 52 | |
64 | lua_CFunction f=(lua_CFunction) dlsym(lib,init); | 53 | static void *ll_load (lua_State *L, const char *path) { |
65 | if (f != NULL) { | 54 | void *lib = dlopen(path, RTLD_NOW); |
66 | registerlib(L, lib); | 55 | if (lib == NULL) lua_pushstring(L, dlerror()); |
67 | lua_pushcfunction(L,f); | 56 | return lib; |
68 | return 0; | ||
69 | } | ||
70 | } | ||
71 | /* else return appropriate error message */ | ||
72 | lua_pushstring(L,dlerror()); | ||
73 | if (lib != NULL) { | ||
74 | dlclose(lib); | ||
75 | return ERR_FUNCTION; /* error loading function */ | ||
76 | } | ||
77 | else return ERR_OPEN; /* error loading library */ | ||
78 | } | 57 | } |
79 | 58 | ||
80 | 59 | ||
60 | static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { | ||
61 | lua_CFunction f = (lua_CFunction)dlsym(lib, sym); | ||
62 | if (f == NULL) lua_pushstring(L, dlerror()); | ||
63 | return f; | ||
64 | } | ||
65 | |||
66 | /* }====================================================== */ | ||
67 | |||
68 | |||
81 | 69 | ||
82 | #elif defined(USE_DLL) | 70 | #elif defined(USE_DLL) |
83 | /* | 71 | /* |
84 | * This is an implementation of loadlib for Windows using native functions. | 72 | ** {====================================================================== |
73 | ** This is an implementation of loadlib for Windows using native functions. | ||
74 | ** ======================================================================= | ||
85 | */ | 75 | */ |
86 | 76 | ||
87 | #include <windows.h> | 77 | #include <windows.h> |
88 | 78 | ||
89 | #define freelib(lib) FreeLibrary((HINSTANCE)lib) | ||
90 | |||
91 | 79 | ||
92 | static void pusherror(lua_State *L) { | 80 | static void pusherror (lua_State *L) { |
93 | int error = GetLastError(); | 81 | int error = GetLastError(); |
94 | char buffer[128]; | 82 | char buffer[128]; |
95 | if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, | 83 | if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, |
96 | 0, error, 0, buffer, sizeof(buffer), 0)) | 84 | NULL, error, 0, buffer, sizeof(buffer), NULL)) |
97 | lua_pushstring(L,buffer); | 85 | lua_pushstring(L,buffer); |
98 | else | 86 | else |
99 | lua_pushfstring(L, "system error %d\n", error); | 87 | lua_pushfstring(L, "system error %d\n", error); |
100 | } | 88 | } |
101 | 89 | ||
90 | static void ll_unloadlib (void *lib) { | ||
91 | FreeLibrary((HINSTANCE)lib); | ||
92 | } | ||
102 | 93 | ||
103 | static int loadlib (lua_State *L, const char *path, const char *init) { | 94 | |
95 | static void *ll_load (lua_State *L, const char *path) { | ||
104 | HINSTANCE lib = LoadLibrary(path); | 96 | HINSTANCE lib = LoadLibrary(path); |
105 | if (lib != NULL) { | 97 | if (lib == NULL) pusherror(L); |
106 | lua_CFunction f = (lua_CFunction)GetProcAddress(lib, init); | 98 | return lib; |
107 | if (f != NULL) { | ||
108 | registerlib(L, lib); | ||
109 | lua_pushcfunction(L, f); | ||
110 | return 0; | ||
111 | } | ||
112 | } | ||
113 | pusherror(L); | ||
114 | if (lib != NULL) { | ||
115 | FreeLibrary(lib); | ||
116 | return ERR_OPEN; | ||
117 | } | ||
118 | else return ERR_FUNCTION; | ||
119 | } | 99 | } |
120 | 100 | ||
121 | 101 | ||
102 | static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { | ||
103 | lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym); | ||
104 | if (f == NULL) pusherror(L); | ||
105 | return f; | ||
106 | } | ||
107 | |||
108 | /* }====================================================== */ | ||
109 | |||
110 | |||
122 | 111 | ||
123 | /* Native Mac OS X / Darwin Implementation */ | ||
124 | #elif defined(USE_DYLD) | 112 | #elif defined(USE_DYLD) |
113 | /* | ||
114 | ** {====================================================================== | ||
115 | ** Native Mac OS X / Darwin Implementation | ||
116 | ** ======================================================================= | ||
117 | */ | ||
125 | 118 | ||
126 | #include <mach-o/dyld.h> | 119 | #include <mach-o/dyld.h> |
127 | 120 | ||
128 | 121 | ||
129 | /* Mach cannot unload images (?) */ | 122 | #undef POF |
130 | #define freelib(lib) ((void)lib) | 123 | #define POF "_" LUA_POF |
131 | 124 | ||
132 | 125 | ||
133 | static void pusherror (lua_State *L) { | 126 | static void pusherror (lua_State *L) { |
@@ -140,86 +133,155 @@ static void pusherror (lua_State *L) { | |||
140 | } | 133 | } |
141 | 134 | ||
142 | 135 | ||
143 | static int loadlib (lua_State *L, const char *path, const char *init) { | 136 | static const char *errorfromcode (NSObjectFileImageReturnCode ret) { |
144 | const struct mach_header *lib; | 137 | switch (ret) { |
138 | case NSObjectFileImageInappropriateFile: | ||
139 | return "file is not a bundle"; | ||
140 | case NSObjectFileImageArch: | ||
141 | return "library is for wrong CPU type"; | ||
142 | case NSObjectFileImageFormat: | ||
143 | return "bad format"; | ||
144 | case NSObjectFileImageAccess: | ||
145 | return "cannot access file"; | ||
146 | case NSObjectFileImageFailure: | ||
147 | default: | ||
148 | return "unable to load library"; | ||
149 | } | ||
150 | } | ||
151 | |||
152 | |||
153 | static void ll_unloadlib (void *lib) { | ||
154 | NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES); | ||
155 | } | ||
156 | |||
157 | |||
158 | static void *ll_load (lua_State *L, const char *path) { | ||
159 | NSObjectFileImage img; | ||
160 | NSObjectFileImageReturnCode ret; | ||
145 | /* this would be a rare case, but prevents crashing if it happens */ | 161 | /* this would be a rare case, but prevents crashing if it happens */ |
146 | if(!_dyld_present()) { | 162 | if(!_dyld_present()) { |
147 | lua_pushstring(L, "dyld not present."); | 163 | lua_pushliteral(L, "dyld not present"); |
148 | return ERR_OPEN; | 164 | return NULL; |
149 | } | 165 | } |
150 | lib = NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR); | 166 | ret = NSCreateObjectFileImageFromFile(path, &img); |
151 | if(lib != NULL) { | 167 | if (ret == NSObjectFileImageSuccess) { |
152 | NSSymbol init_sym = NSLookupSymbolInImage(lib, init, | 168 | NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | |
153 | NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | | 169 | NSLINKMODULE_OPTION_RETURN_ON_ERROR); |
154 | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); | 170 | NSDestroyObjectFileImage(img); |
155 | if(init_sym != NULL) { | 171 | if (mod == NULL) pusherror(L); |
156 | lua_CFunction f = (lua_CFunction)NSAddressOfSymbol(init_sym); | 172 | return mod; |
157 | registerlib(L, lib); | 173 | } |
158 | lua_pushcfunction(L, f); | 174 | lua_pushstring(L, errorfromcode(ret)); |
159 | return 0; | 175 | return NULL; |
160 | } | 176 | } |
177 | |||
178 | |||
179 | static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { | ||
180 | NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym); | ||
181 | if (nss == NULL) { | ||
182 | lua_pushfstring(L, "symbol `%s' not found", sym); | ||
183 | return NULL; | ||
161 | } | 184 | } |
162 | /* else an error ocurred */ | 185 | return (lua_CFunction)NSAddressOfSymbol(nss); |
163 | pusherror(L); | ||
164 | /* Can't unload image */ | ||
165 | return (lib != NULL) ? ERR_FUNCTION : ERR_OPEN; | ||
166 | } | 186 | } |
167 | 187 | ||
188 | /* }====================================================== */ | ||
189 | |||
168 | 190 | ||
169 | 191 | ||
170 | #else | 192 | #else |
171 | /* Fallback for other systems */ | 193 | /* |
194 | ** {====================================================== | ||
195 | ** Fallback for other systems | ||
196 | ** ======================================================= | ||
197 | */ | ||
172 | 198 | ||
199 | #undef LIB_FAIL | ||
200 | #define LIB_FAIL "absent" | ||
173 | 201 | ||
174 | #define freelib(lib) ((void)lib) | ||
175 | 202 | ||
176 | static int loadlib (lua_State *L, const char *path, const char *init) { | 203 | static void ll_unloadlib (void *lib) { |
177 | (void)path; (void)init; (void)®isterlib; /* to avoid warnings */ | 204 | (void)lib; /* to avoid warnings */ |
205 | } | ||
206 | |||
207 | |||
208 | static void *ll_load (lua_State *L, const char *path) { | ||
209 | (void)path; /* to avoid warnings */ | ||
210 | lua_pushliteral(L,"`loadlib' not supported"); | ||
211 | return NULL; | ||
212 | } | ||
213 | |||
214 | |||
215 | static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { | ||
216 | (void)lib; (void)sym; /* to avoid warnings */ | ||
178 | lua_pushliteral(L,"`loadlib' not supported"); | 217 | lua_pushliteral(L,"`loadlib' not supported"); |
179 | return ERR_ABSENT; | 218 | return NULL; |
180 | } | 219 | } |
181 | 220 | ||
221 | /* }====================================================== */ | ||
182 | #endif | 222 | #endif |
183 | 223 | ||
184 | 224 | ||
185 | /* | 225 | |
186 | ** common code for all implementations: put a library into the registry | 226 | static void **ll_register (lua_State *L, const char *path) { |
187 | ** so that, when Lua closes its state, the library's __gc metamethod | 227 | void **plib; |
188 | ** will be called to unload the library. | 228 | lua_pushfstring(L, "%s%s", LIBPREFIX, path); |
189 | */ | 229 | lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ |
190 | static void registerlib (lua_State *L, const void *lib) { | 230 | if (!lua_isnil(L, -1)) /* is there an entry? */ |
191 | const void **plib = (const void **)lua_newuserdata(L, sizeof(const void *)); | 231 | plib = (void **)lua_touserdata(L, -1); |
192 | *plib = lib; | 232 | else { /* no entry yet; create one */ |
193 | luaL_getmetatable(L, "_LOADLIB"); | 233 | lua_pop(L, 1); |
194 | lua_setmetatable(L, -2); | 234 | plib = (void **)lua_newuserdata(L, sizeof(const void *)); |
195 | lua_pushboolean(L, 1); | 235 | *plib = NULL; |
196 | lua_settable(L, LUA_REGISTRYINDEX); /* registry[lib] = true */ | 236 | luaL_getmetatable(L, "_LOADLIB"); |
237 | lua_setmetatable(L, -2); | ||
238 | lua_pushfstring(L, "%s%s", LIBPREFIX, path); | ||
239 | lua_pushvalue(L, -2); | ||
240 | lua_settable(L, LUA_REGISTRYINDEX); | ||
241 | } | ||
242 | return plib; | ||
197 | } | 243 | } |
198 | 244 | ||
245 | |||
199 | /* | 246 | /* |
200 | ** __gc tag method: calls library's `freelib' function with the lib | 247 | ** __gc tag method: calls library's `ll_unloadlib' function with the lib |
201 | ** handle | 248 | ** handle |
202 | */ | 249 | */ |
203 | static int gctm (lua_State *L) { | 250 | static int gctm (lua_State *L) { |
204 | void *lib = *(void **)luaL_checkudata(L, 1, "_LOADLIB"); | 251 | void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); |
205 | freelib(lib); | 252 | if (lib) { |
253 | if (*lib) ll_unloadlib(*lib); | ||
254 | *lib = NULL; /* mark library as closed */ | ||
255 | } | ||
206 | return 0; | 256 | return 0; |
207 | } | 257 | } |
208 | 258 | ||
209 | 259 | ||
260 | static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { | ||
261 | const char *reason; | ||
262 | void **reg = ll_register(L, path); | ||
263 | if (*reg == NULL) *reg = ll_load(L, path); | ||
264 | if (*reg == NULL) | ||
265 | reason = LIB_FAIL; | ||
266 | else { | ||
267 | lua_CFunction f = ll_sym(L, *reg, sym); | ||
268 | if (f) { | ||
269 | lua_pushcfunction(L, f); | ||
270 | return 1; /* return function */ | ||
271 | } | ||
272 | reason = "init"; | ||
273 | } | ||
274 | lua_pushnil(L); | ||
275 | lua_insert(L, -2); | ||
276 | lua_pushstring(L, reason); | ||
277 | return 3; /* return nil, ll_error, reason */ | ||
278 | } | ||
279 | |||
280 | |||
210 | static int ll_loadlib (lua_State *L) { | 281 | static int ll_loadlib (lua_State *L) { |
211 | static const char *const errcodes[] = {NULL, "open", "init", "absent"}; | ||
212 | const char *path = luaL_checkstring(L, 1); | 282 | const char *path = luaL_checkstring(L, 1); |
213 | const char *init = luaL_checkstring(L, 2); | 283 | const char *init = luaL_checkstring(L, 2); |
214 | int res = loadlib(L,path,init); | 284 | return ll_loadfunc(L, path, init); |
215 | if (res == 0) /* no error? */ | ||
216 | return 1; /* function is at stack top */ | ||
217 | else { /* error */ | ||
218 | lua_pushnil(L); | ||
219 | lua_insert(L, -2); /* insert nil before error message */ | ||
220 | lua_pushstring(L, errcodes[res]); | ||
221 | return 3; | ||
222 | } | ||
223 | } | 285 | } |
224 | 286 | ||
225 | 287 | ||
@@ -261,8 +323,8 @@ static const char *loadC (lua_State *L, const char *fname, const char *name) { | |||
261 | fname = luaL_searchpath(L, fname, path); | 323 | fname = luaL_searchpath(L, fname, path); |
262 | if (fname == NULL) return path; /* library not found in this path */ | 324 | if (fname == NULL) return path; /* library not found in this path */ |
263 | funcname = luaL_gsub(L, name, ".", LUA_OFSEP); | 325 | funcname = luaL_gsub(L, name, ".", LUA_OFSEP); |
264 | funcname = lua_pushfstring(L, "%s%s", LUA_POF, funcname); | 326 | funcname = lua_pushfstring(L, "%s%s", POF, funcname); |
265 | if (loadlib(L, fname, funcname) != 0) | 327 | if (ll_loadfunc(L, fname, funcname) != 1) |
266 | luaL_error(L, "error loading package `%s' (%s)", name, lua_tostring(L, -1)); | 328 | luaL_error(L, "error loading package `%s' (%s)", name, lua_tostring(L, -1)); |
267 | return NULL; /* library loaded successfully */ | 329 | return NULL; /* library loaded successfully */ |
268 | } | 330 | } |
@@ -400,25 +462,3 @@ LUALIB_API int luaopen_loadlib (lua_State *L) { | |||
400 | return 1; | 462 | return 1; |
401 | } | 463 | } |
402 | 464 | ||
403 | /* | ||
404 | * Here are some links to available implementations of dlfcn and | ||
405 | * interfaces to other native dynamic loaders on top of which loadlib | ||
406 | * could be implemented. Please send contributions and corrections to us. | ||
407 | * | ||
408 | * AIX | ||
409 | * Starting with AIX 4.2, dlfcn is included in the base OS. | ||
410 | * There is also an emulation package available. | ||
411 | * http://www.faqs.org/faqs/aix-faq/part4/section-21.html | ||
412 | * | ||
413 | * HPUX | ||
414 | * HPUX 11 has dlfcn. For HPUX 10 use shl_*. | ||
415 | * http://www.geda.seul.org/mailinglist/geda-dev37/msg00094.html | ||
416 | * http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html | ||
417 | * | ||
418 | * Macintosh, Windows | ||
419 | * http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html | ||
420 | * | ||
421 | * GLIB has wrapper code for BeOS, OS2, Unix and Windows | ||
422 | * http://cvs.gnome.org/lxr/source/glib/gmodule/ | ||
423 | * | ||
424 | */ | ||