aboutsummaryrefslogtreecommitdiff
path: root/loadlib.c
diff options
context:
space:
mode:
Diffstat (limited to 'loadlib.c')
-rw-r--r--loadlib.c324
1 files changed, 182 insertions, 142 deletions
diff --git a/loadlib.c b/loadlib.c
index ff946429..a74b6a9c 100644
--- a/loadlib.c
+++ b/loadlib.c
@@ -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
30static void ll_unloadlib (void *lib);
31static void *ll_load (lua_State *L, const char *path);
32static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym);
45 33
46static 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 48static void ll_unloadlib (void *lib) {
60 49 dlclose(lib);
61static 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); 53static 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
60static 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
92static void pusherror(lua_State *L) { 80static 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
90static void ll_unloadlib (void *lib) {
91 FreeLibrary((HINSTANCE)lib);
92}
102 93
103static int loadlib (lua_State *L, const char *path, const char *init) { 94
95static 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
102static 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
133static void pusherror (lua_State *L) { 126static void pusherror (lua_State *L) {
@@ -140,86 +133,155 @@ static void pusherror (lua_State *L) {
140} 133}
141 134
142 135
143static int loadlib (lua_State *L, const char *path, const char *init) { 136static 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
153static void ll_unloadlib (void *lib) {
154 NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
155}
156
157
158static 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
179static 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
176static int loadlib (lua_State *L, const char *path, const char *init) { 203static void ll_unloadlib (void *lib) {
177 (void)path; (void)init; (void)&registerlib; /* to avoid warnings */ 204 (void)lib; /* to avoid warnings */
205}
206
207
208static 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
215static 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 226static 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? */
190static 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*/
203static int gctm (lua_State *L) { 250static 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
260static 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
210static int ll_loadlib (lua_State *L) { 281static 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*/